diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/AbstractSemanticValidationRule.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/AbstractSemanticValidationRule.java index 096cccbb3..9010db3e7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/AbstractSemanticValidationRule.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/AbstractSemanticValidationRule.java @@ -7,6 +7,10 @@ public abstract class AbstractSemanticValidationRule implements SemanticValidati protected abstract String getDiagnosticSource(); protected QueryDiagnostic buildOutOfScopeDiagnostic(String variableName, String clause) { + return buildOutOfScopeDiagnostic(getDiagnosticSource(), variableName, clause); + } + + public static QueryDiagnostic buildOutOfScopeDiagnostic(String source, String variableName, String clause) { return new QueryDiagnostic( QueryDiagnostic.Kind.SEMANTIC_ERROR, QueryDiagnostic.Severity.ERROR, @@ -14,6 +18,22 @@ protected QueryDiagnostic buildOutOfScopeDiagnostic(String variableName, String -1, -1, "?" + variableName, - getDiagnosticSource()); + source); + } + + protected QueryDiagnostic buildIncorrectTypeDiagnostic(String variableName, String clause, String expectedType) { + return buildIncorrectTypeDiagnostic(getDiagnosticSource(), variableName, clause, expectedType); + } + + public static QueryDiagnostic buildIncorrectTypeDiagnostic(String source, String variableName, String clause, String expectedType) { + return new QueryDiagnostic( + QueryDiagnostic.Kind.SEMANTIC_ERROR, + QueryDiagnostic.Severity.ERROR, + variableName + " used in " + clause + " should be resolvable to a " + expectedType, + -1, + -1, + variableName, + source); } + } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/FilterArgumentsValidationRule.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/FilterArgumentsValidationRule.java new file mode 100644 index 000000000..4ebe45ba3 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/FilterArgumentsValidationRule.java @@ -0,0 +1,54 @@ +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.*; +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.checkTermIsPotentialBoolean; + +/** + * This rule checks the operators used in Filter asts + */ +public final class FilterArgumentsValidationRule extends AbstractSemanticValidationRule { + + @Override + protected String getDiagnosticSource() { + return FilterArgumentsValidationRule.class.getSimpleName(); + } + + @Override + public List validate(QueryAst queryAst) { + FilterArgumentsValidationVisitor visitor = new FilterArgumentsValidationVisitor(); + queryAst.accept(visitor); + return visitor.getResult(); + } + + private class FilterArgumentsValidationVisitor extends AbstractAstVisitor { + private final List result = new ArrayList<>(); + + public List getResult() { + return result; + } + + @Override + public void visit(PatternAst patternAst) { + if (patternAst instanceof FilterAst(TermAst operator) && !checkTermIsPotentialBoolean(operator)) { + result.add(buildIncorrectTypeDiagnostic(operator.getName(), "FILTER", "boolean")); + } + } + + @Override + public void visit(HavingAst havingAst) { + for (TermAst condition : havingAst.conditions()) { + if (!checkTermIsPotentialBoolean(condition)) { + result.add(buildIncorrectTypeDiagnostic(condition.getName(), "HAVING", "boolean")); + } + } + } + } +} + diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentBooleanTypeValidationRule.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentBooleanTypeValidationRule.java new file mode 100644 index 000000000..2f9ebfa8c --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentBooleanTypeValidationRule.java @@ -0,0 +1,57 @@ +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.checkTermIsPotentialBoolean; + +public class OperandArgumentBooleanTypeValidationRule extends AbstractSemanticValidationRule { + @Override + protected String getDiagnosticSource() { + return OperandArgumentBooleanTypeValidationRule.class.getSimpleName(); + } + + @Override + public List validate(QueryAst queryAst) { + OperandBooleanArgumentTypeVisitor visitor = new OperandBooleanArgumentTypeVisitor(); + queryAst.accept(visitor); + return visitor.getResult(); + } + + private class OperandBooleanArgumentTypeVisitor extends AbstractAstVisitor { + private final List result = new ArrayList<>(); + + public List getResult() { + return result; + } + + @Override + public void visit(TermAst termAst) { + if(termAst instanceof BooleanNotAst booleanNotAst) { + if(! checkTermIsPotentialBoolean( booleanNotAst.argument())) { + result.add(buildIncorrectTypeDiagnostic(booleanNotAst.argument().getName(), booleanNotAst.getName(), "boolean")); + } + } + if(termAst instanceof BinaryConstraintAst binaryConstraintAst) { + if(binaryConstraintAst instanceof AndAst + || binaryConstraintAst instanceof OrAst) { + if(! checkTermIsPotentialBoolean( binaryConstraintAst.getLeftArgument())) { + result.add(buildIncorrectTypeDiagnostic(binaryConstraintAst.getLeftArgument().getName(), binaryConstraintAst.getName(), "boolean")); + } + if(! checkTermIsPotentialBoolean( binaryConstraintAst.getRightArgument())) { + result.add(buildIncorrectTypeDiagnostic(binaryConstraintAst.getRightArgument().getName(), binaryConstraintAst.getName(), "boolean")); + } + } + } + } + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentIRITypeValidationRule.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentIRITypeValidationRule.java new file mode 100644 index 000000000..4175f750c --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentIRITypeValidationRule.java @@ -0,0 +1,56 @@ +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.checkTermIsPotentialIri; + +/** + * 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 validate(QueryAst queryAst) { + OperandIRIArgumentTypeVisitor visitor = new OperandIRIArgumentTypeVisitor(); + queryAst.accept(visitor); + return visitor.getResult(); + } + + private class OperandIRIArgumentTypeVisitor extends AbstractAstVisitor { + private final List result = new ArrayList<>(); + + public List getResult() { + return result; + } + + @Override + public void visit(TermAst termAst) { + if(termAst instanceof BinaryConstraintAst binaryConstraintAst) { + if(binaryConstraintAst instanceof LowerThanAst + || binaryConstraintAst instanceof LowerOrEqualThanAst + || binaryConstraintAst instanceof GreaterThanAst + || binaryConstraintAst instanceof GreaterOrEqualThanAst) { + if(checkTermIsPotentialIri(binaryConstraintAst.getLeftArgument())) { + result.add(buildIncorrectTypeDiagnostic(binaryConstraintAst.getLeftArgument().getName(), binaryConstraintAst.getName(), "not an IRI")); + } + if(checkTermIsPotentialIri(binaryConstraintAst.getRightArgument())) { + result.add(buildIncorrectTypeDiagnostic(binaryConstraintAst.getRightArgument().getName(), binaryConstraintAst.getName(), "not an IRI")); + } + } + } + } + } + +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentNumericTypeValidationRule.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentNumericTypeValidationRule.java new file mode 100644 index 000000000..a2a1b38f4 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/rule/OperandArgumentNumericTypeValidationRule.java @@ -0,0 +1,69 @@ +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.checkTermIsPotentialNumeric; + +/** + * Check that the operands and numeric functions use numeric arguments + */ +public final class OperandArgumentNumericTypeValidationRule extends AbstractSemanticValidationRule { + + @Override + protected String getDiagnosticSource() { + return OperandArgumentNumericTypeValidationRule.class.getSimpleName(); + } + + @Override + public List validate(QueryAst queryAst) { + OperandNumericArgumentTypeVisitor visitor = new OperandNumericArgumentTypeVisitor(); + queryAst.accept(visitor); + return visitor.getResult(); + } + + private class OperandNumericArgumentTypeVisitor extends AbstractAstVisitor { + private final List result = new ArrayList<>(); + + public List getResult() { + return result; + } + + @Override + public void visit(TermAst termAst) { + if (termAst instanceof UnaryConstraintAst unaryConstraintAst) { + if ( + (unaryConstraintAst instanceof AbsAst + || unaryConstraintAst instanceof CeilAst + || unaryConstraintAst instanceof FloorAst + || unaryConstraintAst instanceof RoundAst + || unaryConstraintAst instanceof UnaryMinusAst + || unaryConstraintAst instanceof UnaryPlusAst) + && !checkTermIsPotentialNumeric(unaryConstraintAst.argument())) { + result.add(buildIncorrectTypeDiagnostic(unaryConstraintAst.argument().getName(), unaryConstraintAst.getName(), "numeric")); + } + } + + if (termAst instanceof BinaryConstraintAst binaryConstraintAst) { // Numeric only operands + if (binaryConstraintAst instanceof AddAst + || binaryConstraintAst instanceof DivideAst + || binaryConstraintAst instanceof MultiplyAst + || binaryConstraintAst instanceof SubtractAst + ) { + if (!checkTermIsPotentialNumeric(binaryConstraintAst.getLeftArgument())) { + result.add(buildIncorrectTypeDiagnostic(binaryConstraintAst.getLeftArgument().getName(), binaryConstraintAst.getName(), "numeric")); + } + if (!checkTermIsPotentialNumeric(binaryConstraintAst.getRightArgument())) { + result.add(buildIncorrectTypeDiagnostic(binaryConstraintAst.getRightArgument().getName(), binaryConstraintAst.getName(), "numeric")); + } + } + } + } + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/AbstractAstVisitor.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/AbstractAstVisitor.java new file mode 100644 index 000000000..fd5aff3c3 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/AbstractAstVisitor.java @@ -0,0 +1,104 @@ +package fr.inria.corese.core.next.query.impl.parser.semantic.support; + +import fr.inria.corese.core.next.query.impl.sparql.ast.*; + +/** + * Default implementation for AstVisitor + */ +public abstract class AbstractAstVisitor implements AstVisitor { + + @Override + public void visit(PatternAst ast) { + + } + + @Override + public void visit(QueryAst ast) { + + } + + @Override + public void visit(UpdateRequestUnitAst ast) { + + } + + @Override + public void visit(TermAst ast) { + + } + + @Override + public void visit(ProjectionAst ast) { + + } + + @Override + public void visit(QueryPrologueAst ast) { + + } + + @Override + public void visit(ValuesAst ast) { + + } + + @Override + public void visit(ValueMappingAst ast) { + + } + + @Override + public void visit(SolutionModifierAst ast) { + + } + + @Override + public void visit(GroupGraphPatternAst ast) { + + } + + @Override + public void visit(TriplePatternAst ast) { + + } + + @Override + public void visit(ConstructTemplateAst ast) { + + } + + @Override + public void visit(DatasetClauseAst ast) { + + } + + @Override + public void visit(GroupByAst ast) { + + } + + @Override + public void visit(HavingAst ast) { + + } + + @Override + public void visit(OrderConditionAst ast) { + + } + + @Override + public void visit(PrefixDeclarationAst ast) { + + } + + @Override + public void visit(ServiceAst ast) { + + } + + @Override + public void visit(GraphRefAst ast) { + + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/AstVisitor.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/AstVisitor.java new file mode 100644 index 000000000..c36f05433 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/AstVisitor.java @@ -0,0 +1,28 @@ +package fr.inria.corese.core.next.query.impl.parser.semantic.support; + +import fr.inria.corese.core.next.query.impl.sparql.ast.*; + +/** + * Visitor interface for the AST hierarchy + */ +public interface AstVisitor { + void visit(PatternAst ast); + void visit(QueryAst ast); + void visit(UpdateRequestUnitAst ast); + void visit(TermAst ast); + void visit(ProjectionAst ast); + void visit(QueryPrologueAst ast); + void visit(ValuesAst ast); + void visit(ValueMappingAst ast); + void visit(SolutionModifierAst ast); + void visit(GroupGraphPatternAst ast); + void visit(TriplePatternAst ast); + void visit(ConstructTemplateAst ast); + void visit(DatasetClauseAst ast); + void visit(GroupByAst ast); + void visit(HavingAst ast); + void visit(OrderConditionAst ast); + void visit(PrefixDeclarationAst ast); + void visit(ServiceAst ast); + void visit(GraphRefAst ast); +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/SemanticValidationUtils.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/SemanticValidationUtils.java new file mode 100644 index 000000000..fed41d58c --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/SemanticValidationUtils.java @@ -0,0 +1,143 @@ +package fr.inria.corese.core.next.query.impl.parser.semantic.support; + +import fr.inria.corese.core.next.data.impl.common.vocabulary.XSD; +import fr.inria.corese.core.next.query.impl.sparql.ast.IriAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.LiteralAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*; + +import java.util.List; + +public class SemanticValidationUtils { + + /** + * Valid numeric datatypes as defined in https://www.w3.org/TR/sparql11-query/#operandDataTypes + */ + private static final List validNumericDatatypes = List.of( + XSD.xsdInteger.getIRI().stringValue(), + XSD.xsdDecimal.getIRI().stringValue(), + XSD.xsdFloat.getIRI().stringValue(), + XSD.xsdDouble.getIRI().stringValue(), + XSD.xsdNonPositiveInteger.getIRI().stringValue(), + XSD.xsdNegativeInteger.getIRI().stringValue(), + XSD.xsdLong.getIRI().stringValue(), + XSD.xsdInt.getIRI().stringValue(), + XSD.xsdShort.getIRI().stringValue(), + XSD.xsdByte.getIRI().stringValue(), + XSD.xsdNonNegativeInteger.getIRI().stringValue(), + XSD.xsdUnsignedLong.getIRI().stringValue(), + XSD.xsdUnsignedInt.getIRI().stringValue(), + XSD.xsdUnsignedShort.getIRI().stringValue(), + XSD.xsdUnsignedByte.getIRI().stringValue(), + XSD.xsdPositiveInteger.getIRI().stringValue() + ); + + /** + * Check that the given term is either boolean expression, literal expression (that may return a boolean result) or a variable + */ + public static boolean checkTermIsPotentialBoolean(TermAst termAst) { + if (checkTermIsUnknownType(termAst)) { + return true; + } + if (termAst instanceof BooleanExpressionAst) { + return true; + } + if (termAst instanceof LiteralExpressionAst literalExpressionAst + && !(literalExpressionAst instanceof XsdDateTimeExpressionAst + || literalExpressionAst instanceof XsdDayTimeDurationExpressionAst + || literalExpressionAst instanceof NumericExpressionAst + )) { // Is a literal expression that could be a boolean, we cannot know + return true; + } + if (termAst instanceof IfAst ifAst + && checkTermIsPotentialBoolean(ifAst.thenExpr()) + && checkTermIsPotentialBoolean(ifAst.elseExpr())) { // Is a IF that returns potential booleans + return true; + } + if (termAst instanceof LiteralAst( + String lexical, String lang, String datatype + )) {// is a literal that is a typed as a boolean or the string representation of one + if (datatype != null) { + return datatype.equals(XSD.xsdBoolean.getIRI().stringValue()); + } else { + return lexical.trim().equalsIgnoreCase("true") || lexical.trim().equalsIgnoreCase("false"); + } + } + + return false; + } + + + /** + * Check that the given term is either numeric expression, literal expression typed by a standard numeric datatype, a literal that can be parsed to a numeric or a variable + */ + public static boolean checkTermIsPotentialNumeric(TermAst termAst) { + if (checkTermIsUnknownType(termAst)) { + return true; + } + if (termAst instanceof IfAst ifAst + && checkTermIsPotentialNumeric(ifAst.thenExpr()) + && checkTermIsPotentialNumeric(ifAst.elseExpr())) { // Is an IF that returns potential numerics + return true; + } + if (termAst instanceof NumericExpressionAst) { // Is a literal expression that could be a numeric, we cannot know + return true; + } + if (termAst instanceof LiteralAst(String lexical, String lang, String datatype)) { + if(datatype != null) { + return validNumericDatatypes.contains(datatype); // Datatype is an URI of an standard numeric datatype + } else { + return checkStringIsNumeric(lexical); // The string value can be parsed to a numeric value + } + } + + return false; + } + + /** + * Check if the given term type cannot be determined at query parsing, it will be checked at query resolution. + * + */ + public static boolean checkTermIsUnknownType(TermAst termAst) { + if (termAst instanceof VarAst) { // Is a variable that can be resolved to a boolean + return true; + } + if (termAst instanceof FunctionCallAst) { // Is a function call that could return a boolean, we cannot know + return true; + } + if(termAst instanceof SimpleLiteralExpressionAst) { // Could be a string un-typed but still representing a known type. will be filtered at resolution + return true; + } + + return false; + } + + /** + * Tries to parse the string as a Double + */ + public static boolean checkStringIsNumeric(String lexical) { + if (lexical == null) { + return false; + } + try { + double d = Double.parseDouble(lexical); + } catch (NumberFormatException nfe) { + return false; + } + return true; + } + + /** + * Check if the term is either a variable or an IRI or an expression that can be resolved to an IRI + */ + public static boolean checkTermIsPotentialIri(TermAst termAst) { + if(termAst instanceof IriAst) { // Is an IRI + return true; + } + if(termAst instanceof IriExpressionAst) { // Is a function that can be resolved to an IRI + return true; + } + return false; + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VariableScopeAnalyzer.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VariableScopeAnalyzer.java index 79b29015c..0f9e1fd6d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VariableScopeAnalyzer.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VariableScopeAnalyzer.java @@ -164,7 +164,7 @@ private void collectReferencedVariables(TermAst term, Set referencedVari // Recurse into unary expressions such as STR(?x) or BOUND(?x). case UnaryConstraintAst unaryConstraint -> - collectReferencedVariables(unaryConstraint.getArgument(), referencedVariables); + collectReferencedVariables(unaryConstraint.argument(), referencedVariables); case BinaryConstraintAst binaryConstraint -> { // Recurse into both operands of binary expressions. @@ -218,14 +218,14 @@ case IfAst(TermAst condition, TermAst thenExpr, TermAst elseExpr) -> { collectReferencedVariables(elseExpr, referencedVariables); } - case CoalesceAst(List arguments) -> { - for (TermAst argument : arguments) { + case CoalesceAst coalesceAst -> { + for (TermAst argument : coalesceAst.arguments()) { collectReferencedVariables(argument, referencedVariables); } } - case ConcatAst(List arguments) -> { - for (TermAst argument : arguments) { + case ConcatAst concatAst -> { + for (TermAst argument : concatAst.arguments()) { collectReferencedVariables(argument, referencedVariables); } } @@ -244,8 +244,6 @@ case NotInAst(TermAst left, List candidates) -> { } } - case StrLenAst(TermAst argument) -> collectReferencedVariables(argument, referencedVariables); - case AggregateAst( AggregateFunction ignoredFunction, boolean ignoredDistinct, TermAst expression, String ignoredSep) -> collectReferencedVariables(expression, referencedVariables); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VisitableAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VisitableAst.java new file mode 100644 index 000000000..9ee4db540 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/VisitableAst.java @@ -0,0 +1,6 @@ +package fr.inria.corese.core.next.query.impl.parser.semantic.support; + +public interface VisitableAst { + + void accept(AstVisitor visitor); +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/validator/SparqlQuerySemanticValidator.java b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/validator/SparqlQuerySemanticValidator.java index 9661c1f12..7989a06bd 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/validator/SparqlQuerySemanticValidator.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/parser/semantic/validator/SparqlQuerySemanticValidator.java @@ -3,9 +3,7 @@ import fr.inria.corese.core.next.query.api.validation.QueryDiagnostic; import fr.inria.corese.core.next.query.api.validation.QueryValidationResult; import fr.inria.corese.core.next.query.api.validation.QueryValidator; -import fr.inria.corese.core.next.query.impl.parser.semantic.rule.OrderByScopeValidationRule; -import fr.inria.corese.core.next.query.impl.parser.semantic.rule.SelectProjectionScopeValidationRule; -import fr.inria.corese.core.next.query.impl.parser.semantic.rule.SemanticValidationRule; +import fr.inria.corese.core.next.query.impl.parser.semantic.rule.*; import fr.inria.corese.core.next.query.impl.sparql.ast.QueryAst; import java.util.ArrayList; @@ -22,7 +20,11 @@ public final class SparqlQuerySemanticValidator implements QueryValidator triples) implements PatternAst { public BgpAst { triples = triples != null ? List.copyOf(triples) : List.of(); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + triples.forEach(triplePatternAst -> { + triplePatternAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/BindAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/BindAst.java index 2fea14899..d58341b10 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/BindAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/BindAst.java @@ -1,6 +1,19 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * BIND(expression AS ?var) clause in SPARQL 1.1 */ -public record BindAst(TermAst expression, VarAst variable) implements PatternAst {} \ No newline at end of file +public record BindAst(TermAst expression, VarAst variable) implements PatternAst { + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + if(this.expression != null) { + expression.accept(visitor); + } + if(this.variable != null) { + variable.accept(visitor); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ClearRequestAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ClearRequestAst.java index e1e8657fc..ff9b86002 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ClearRequestAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ClearRequestAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * Represents the CLEAR operation as defined in the SPARQL 1.1 recommendation. * @param graphRef targeted graph to be cleared @@ -13,4 +15,10 @@ public record ClearRequestAst(GraphRefAst graphRef, boolean silent) implements U public ClearRequestAst(GraphRefAst graphRef) { this( graphRef, false); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.graphRef.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstraintAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstraintAst.java index f8dde56d5..159ed5120 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstraintAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstraintAst.java @@ -1,7 +1,9 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * Root interface for all operators resolving to a term */ -public non-sealed interface ConstraintAst extends TermAst { +public non-sealed interface ConstraintAst extends TermAst, VisitableAst { } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructQueryAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructQueryAst.java index 3a2345d38..6fd005e6f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructQueryAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructQueryAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + import java.util.List; /** @@ -72,4 +74,15 @@ public ConstructQueryAst(ConstructTemplateAst template, DatasetClauseAst dataset public ConstructQueryAst(ConstructTemplateAst template, GroupGraphPatternAst whereClause) { this(template, DatasetClauseAst.none(), whereClause, SolutionModifierAst.empty(), null, null); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.constructTemplate.accept(visitor); + this.datasetClause.accept(visitor); + this.whereClause.accept(visitor); + this.solutionModifier.accept(visitor); + this.prologue.accept(visitor); + this.valuesClause.accept(visitor); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructTemplateAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructTemplateAst.java index ff2c9e878..a51e9e919 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructTemplateAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ConstructTemplateAst.java @@ -1,5 +1,8 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.List; /** @@ -12,8 +15,16 @@ * * @param triplePatternAsts triples to instantiate from solution bindings */ -public record ConstructTemplateAst(List triplePatternAsts) { +public record ConstructTemplateAst(List triplePatternAsts) implements VisitableAst { public ConstructTemplateAst { triplePatternAsts = triplePatternAsts != null ? List.copyOf(triplePatternAsts) : List.of(); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.triplePatternAsts.forEach(triplePatternAst -> { + triplePatternAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DatasetClauseAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DatasetClauseAst.java index 10571fd68..e42bb7b3c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DatasetClauseAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DatasetClauseAst.java @@ -1,9 +1,12 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.LinkedHashSet; import java.util.Set; -public record DatasetClauseAst(Set graphs, Set namedGraphs) { +public record DatasetClauseAst(Set graphs, Set namedGraphs) implements VisitableAst { public DatasetClauseAst { graphs = graphs == null ? Set.of() : Set.copyOf(new LinkedHashSet<>(graphs)); @@ -13,4 +16,15 @@ public record DatasetClauseAst(Set graphs, Set namedGraphs) { public static DatasetClauseAst none() { return new DatasetClauseAst(Set.of(), Set.of()); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.graphs.forEach(iriAst -> { + iriAst.accept(visitor); + }); + this.namedGraphs.forEach(iriAst -> { + iriAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DescribeQueryAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DescribeQueryAst.java index 334b50536..fd65b7fa8 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DescribeQueryAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/DescribeQueryAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + import java.util.List; /** @@ -74,4 +76,17 @@ public DescribeQueryAst(DatasetClauseAst datasetClause, List described, public boolean isDescribeAll() { return described.isEmpty(); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.prologue.accept(visitor); + this.datasetClause.accept(visitor); + this.described.forEach(termAst -> { + termAst.accept(visitor); + }); + this.whereClause.accept(visitor); + this.valuesClause.accept(visitor); + this.solutionModifier.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/FilterAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/FilterAst.java index 227dd4178..cadeddc05 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/FilterAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/FilterAst.java @@ -1,8 +1,15 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * Filter clause in a SPARQL query * @param operator The operator whose evaluation will make a filter a createFunCall on the query results */ public record FilterAst(TermAst operator) implements PatternAst { + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.operator.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GraphRefAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GraphRefAst.java index 97045e296..a962b2770 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GraphRefAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GraphRefAst.java @@ -1,8 +1,10 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; import fr.inria.corese.core.next.query.api.exception.QueryEvaluationException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; -public record GraphRefAst(IriAst graph, boolean named, boolean all, boolean defaultGraph) { +public record GraphRefAst(IriAst graph, boolean named, boolean all, boolean defaultGraph) implements VisitableAst { public GraphRefAst { int activeTargets = 0; if (graph != null) { @@ -33,4 +35,12 @@ public GraphRefAst(IriAst graph) { public GraphRefAst(boolean named, boolean all, boolean defaultGraph) { this(null, named, all, defaultGraph); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + if(this.graph != null) { + this.graph.accept(visitor); + } + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupByAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupByAst.java index fdf122837..3882a0729 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupByAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupByAst.java @@ -1,8 +1,11 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.List; -public record GroupByAst(List expressions) { +public record GroupByAst(List expressions) implements VisitableAst { public GroupByAst { expressions = expressions != null ? List.copyOf(expressions) : List.of(); } @@ -10,4 +13,12 @@ public record GroupByAst(List expressions) { public boolean isEmpty() { return expressions.isEmpty(); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.expressions.forEach(termAst -> { + termAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupGraphPatternAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupGraphPatternAst.java index 8b454730b..cca8f3864 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupGraphPatternAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/GroupGraphPatternAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + import java.util.List; /** @@ -10,4 +12,12 @@ public record GroupGraphPatternAst(List patterns) implements Pattern public GroupGraphPatternAst { patterns = patterns != null ? List.copyOf(patterns) : List.of(); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.patterns.forEach(patternAst -> { + patternAst.accept(visitor); + }); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/HavingAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/HavingAst.java index 1cb313cf3..272372a8b 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/HavingAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/HavingAst.java @@ -1,11 +1,14 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.List; /** * SPARQL {@code HAVING} clause: boolean constraints evaluated after grouping. */ -public record HavingAst(List conditions) { +public record HavingAst(List conditions) implements VisitableAst { public HavingAst { conditions = conditions != null ? List.copyOf(conditions) : List.of(); } @@ -17,4 +20,12 @@ public boolean isEmpty() { public static HavingAst empty() { return new HavingAst(List.of()); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.conditions.forEach(conditionAst -> { + conditionAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/IriAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/IriAst.java index ea96239d0..aa9bfb672 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/IriAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/IriAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * IRI or QName in a triple pattern (e.g. <http://...>, foaf:Person, a). */ @@ -9,4 +11,14 @@ public record IriAst(String raw) implements TermAst { throw new IllegalArgumentException("IRI raw is null"); } } + + @Override + public String getName() { + return this.raw; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LiteralAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LiteralAst.java index 1b67098e4..1d63fba25 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LiteralAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LiteralAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * RDF literal in a triple pattern (lexical form, optional language tag or datatype). */ @@ -9,4 +11,20 @@ public record LiteralAst(String lexical, String lang, String datatype) implement throw new IllegalArgumentException("Literal lexical is null"); } } + + @Override + public String getName() { + if (datatype != null && !datatype.isBlank()) { + return lexical + "^^" + datatype; + } + if (lang != null && !lang.isBlank()) { + return lexical + "@" + lang; + } + return lexical; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LoadRequestAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LoadRequestAst.java index a51ee0d4b..50bff0c90 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LoadRequestAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/LoadRequestAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; import fr.inria.corese.core.next.query.api.exception.QueryEvaluationException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; /** * Represents the LOAD operation as defined in the SPARQL 1.1 recommendation. @@ -24,4 +25,14 @@ public record LoadRequestAst(GraphRefAst fromClause, GraphRefAst toClause, boole public LoadRequestAst(GraphRefAst fromClause, GraphRefAst toClause) { this(fromClause, toClause, false); } + + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.fromClause.accept(visitor); + if(this.toClause != null) { + this.toClause.accept(visitor); + } + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/MinusAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/MinusAst.java index 42433a933..872ebbfce 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/MinusAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/MinusAst.java @@ -1,7 +1,14 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * AST node representing a SPARQL {@code MINUS} graph pattern. */ public record MinusAst(GroupGraphPatternAst pattern) implements PatternAst { + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.pattern.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OptionalAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OptionalAst.java index f78f3d95d..8f1c88f76 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OptionalAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OptionalAst.java @@ -1,8 +1,16 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * Optional can contain BGP, FILTER, UNION * * @param ast PatternAst */ -public record OptionalAst(PatternAst ast) implements PatternAst {} \ No newline at end of file +public record OptionalAst(PatternAst ast) implements PatternAst { + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.ast.accept(visitor); + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OrderConditionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OrderConditionAst.java index bb2eaf65b..7b121379f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OrderConditionAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/OrderConditionAst.java @@ -1,14 +1,23 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * One ORDER BY condition. */ public record OrderConditionAst( ASTConstants.OrderDirection orderDirection, TermAst expression -) { +) implements VisitableAst { public OrderConditionAst { if (orderDirection == null) throw new IllegalArgumentException("direction is null"); if (expression == null) throw new IllegalArgumentException("expression is null"); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.expression.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PatternAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PatternAst.java index 52aab2fbd..baff3db84 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PatternAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PatternAst.java @@ -1,7 +1,11 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * Element of a group graph pattern (BGP, optional, union, etc.). */ -public sealed interface PatternAst permits BgpAst, BindAst, FilterAst, GroupGraphPatternAst, MinusAst, OptionalAst, ServiceAst, UnionAst, SubQueryAst { +public sealed interface PatternAst extends VisitableAst permits BgpAst, BindAst, FilterAst, GroupGraphPatternAst, MinusAst, OptionalAst, ServiceAst, UnionAst, SubQueryAst { + void accept(AstVisitor visitor); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PrefixDeclarationAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PrefixDeclarationAst.java index 8957ffb5c..99e90123a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PrefixDeclarationAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/PrefixDeclarationAst.java @@ -1,5 +1,8 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.Objects; import static fr.inria.corese.core.next.util.StringUtils.trimChevronIRIs; @@ -8,7 +11,7 @@ /** * A {@code PREFIX p: <ns>} declaration from the SPARQL prologue ({@code p} without trailing colon). */ -public record PrefixDeclarationAst(String prefix, IriAst namespace) { +public record PrefixDeclarationAst(String prefix, IriAst namespace) implements VisitableAst { public PrefixDeclarationAst { if (prefix == null ) { throw new IllegalArgumentException("prefix must be non-null"); @@ -19,4 +22,10 @@ public record PrefixDeclarationAst(String prefix, IriAst namespace) { namespace = new IriAst(trimChevronIRIs(namespace.raw())); } } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.namespace.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ProjectionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ProjectionAst.java index 1c867598d..6970700a1 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ProjectionAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ProjectionAst.java @@ -1,5 +1,8 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.List; import java.util.Set; @@ -9,7 +12,7 @@ *

* Use {@link ProjectionAsts#selectAll()} and {@link ProjectionAsts#of(List)} to create instances. */ -public record ProjectionAst(boolean selectAll, List variables, Set expressionBoundVariables) { +public record ProjectionAst(boolean selectAll, List variables, Set expressionBoundVariables) implements VisitableAst { public ProjectionAst { variables = variables != null ? List.copyOf(variables) : List.of(); expressionBoundVariables = expressionBoundVariables != null ? Set.copyOf(expressionBoundVariables) : Set.of(); @@ -20,4 +23,12 @@ public record ProjectionAst(boolean selectAll, List variables, Set { + varAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryAst.java index d5f5ffa7b..038dcbe94 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryAst.java @@ -1,8 +1,10 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * Root interface for an abstract syntax trees for operation */ -public sealed interface QueryAst permits SparqlQueryAst, UpdateRequestAst { +public sealed interface QueryAst extends VisitableAst permits SparqlQueryAst, UpdateRequestAst { QueryPrologueAst prologue(); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryPrologueAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryPrologueAst.java index c6700b411..436c25bca 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryPrologueAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/QueryPrologueAst.java @@ -3,6 +3,8 @@ import fr.inria.corese.core.next.data.impl.common.util.IRIUtils; import fr.inria.corese.core.next.data.impl.io.common.IOConstants; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; import java.util.List; @@ -15,7 +17,7 @@ * For now this type is only attached to {@link SelectQueryAst}; other query forms still expose * prefix/base state via {@link fr.inria.corese.core.next.data.api.IPrefixHandler} on {@link QueryAst}. */ -public record QueryPrologueAst(List prefixDeclarations, IriAst baseIri) { +public record QueryPrologueAst(List prefixDeclarations, IriAst baseIri) implements VisitableAst { public QueryPrologueAst { prefixDeclarations = prefixDeclarations != null ? List.copyOf(prefixDeclarations) : List.of(); @@ -40,4 +42,13 @@ public record QueryPrologueAst(List prefixDeclarations, Ir public static QueryPrologueAst empty() { return new QueryPrologueAst(List.of(), new IriAst(IOConstants.getDefaultBaseURI())); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.prefixDeclarations.forEach(prefixDeclarationAst -> { + prefixDeclarationAst.accept(visitor); + }); + this.baseIri.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SelectQueryAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SelectQueryAst.java index f1f92d103..94c45830c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SelectQueryAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SelectQueryAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + import java.util.List; /** @@ -46,4 +48,15 @@ public SelectQueryAst(ProjectionAst projection, DatasetClauseAst datasetClause, valuesClause = ValuesAst.none(); } } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.projection.accept(visitor); + this.datasetClause.accept(visitor); + this.whereClause.accept(visitor); + this.solutionModifier.accept(visitor); + this.prologue.accept(visitor); + this.valuesClause.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ServiceAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ServiceAst.java index bdcbdacef..581a321b7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ServiceAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ServiceAst.java @@ -1,5 +1,8 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * AST node representing a SPARQL {@code SERVICE} graph pattern. * @@ -11,5 +14,11 @@ * @param silent whether the {@code SILENT} keyword was present * @param pattern the graph pattern to evaluate at the remote endpoint */ -public record ServiceAst(TermAst endpoint, boolean silent, GroupGraphPatternAst pattern) implements PatternAst { +public record ServiceAst(TermAst endpoint, boolean silent, GroupGraphPatternAst pattern) implements VisitableAst, PatternAst { + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.endpoint.accept(visitor); + this.pattern.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SolutionModifierAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SolutionModifierAst.java index b5cc6d0b5..65e2daed2 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SolutionModifierAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SolutionModifierAst.java @@ -1,5 +1,8 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.List; /** @@ -24,7 +27,7 @@ public record SolutionModifierAst( HavingAst having, Long limit, Long offset -) { +) implements VisitableAst { public SolutionModifierAst { groupBy = groupBy != null ? groupBy : new GroupByAst(List.of()); orderBy = orderBy != null ? List.copyOf(orderBy) : List.of(); @@ -76,4 +79,14 @@ public boolean hasLimit() { public boolean hasOffset() { return offset != null; } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + groupBy.accept(visitor); + this.orderBy.forEach(orderConditionAst -> { + orderConditionAst.accept(visitor); + }); + this.having.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SubQueryAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SubQueryAst.java index a4f09b701..ffbb27557 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SubQueryAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/SubQueryAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + public record SubQueryAst(QueryAst query) implements PatternAst { public SubQueryAst { if (query == null) { @@ -10,4 +12,10 @@ public record SubQueryAst(QueryAst query) implements PatternAst { "Only SELECT subqueries are supported in W3C: " + query.getClass().getName()); } } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.query.accept(visitor); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TermAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TermAst.java index 7a752ffd3..d6daec0c1 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TermAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TermAst.java @@ -1,9 +1,12 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * AST node for a SPARQL term (variable, IRI or literal) in a triple pattern. */ -public sealed interface TermAst permits ConstraintAst, IriAst, LiteralAst, VarAst { +public sealed interface TermAst extends VisitableAst permits ConstraintAst, IriAst, LiteralAst, VarAst { + String getName(); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TriplePatternAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TriplePatternAst.java index e3663a5e4..38c8dc327 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TriplePatternAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/TriplePatternAst.java @@ -1,12 +1,23 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * A single triple pattern (s p o) in a BGP. */ -public record TriplePatternAst(TermAst subject, TermAst predicate, TermAst object) { +public record TriplePatternAst(TermAst subject, TermAst predicate, TermAst object) implements VisitableAst { public TriplePatternAst { if (subject == null || predicate == null || object == null) { throw new IllegalArgumentException("subject, predicate and object must be non-null"); } } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.subject.accept(visitor); + this.predicate.accept(visitor); + this.object.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UnionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UnionAst.java index 155b1c81f..464f13e1d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UnionAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UnionAst.java @@ -1,7 +1,15 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * AST node representing a SPARQL {@code UNION} of two graph patterns. */ public record UnionAst(GroupGraphPatternAst left, GroupGraphPatternAst right) implements PatternAst { + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.left.accept(visitor); + this.right.accept(visitor); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestAst.java index 80f308c97..f7994d89c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + import java.util.List; /** @@ -15,4 +17,11 @@ public record UpdateRequestAst(QueryPrologueAst prologue, List updateRequestUnitAst.accept(visitor)); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java index cec57808d..378a8f4aa 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/UpdateRequestUnitAst.java @@ -1,7 +1,9 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + /** * Root interface for all operations related to the SPARQL Update operations listed in SPARQL 1.1 Update. */ -public sealed interface UpdateRequestUnitAst permits LoadRequestAst, ClearRequestAst { +public sealed interface UpdateRequestUnitAst extends VisitableAst permits LoadRequestAst, ClearRequestAst { } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValueMappingAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValueMappingAst.java index f1ffc1cd8..a8bdb72fb 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValueMappingAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValueMappingAst.java @@ -1,5 +1,8 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.HashMap; import java.util.Map; @@ -7,11 +10,24 @@ * Represent one solution mapping for VALUES, in the order it is written. A set of values for variables with null standing for UNDEF. * @param values */ -public record ValueMappingAst(Map values) { +public record ValueMappingAst(Map values) implements VisitableAst { public ValueMappingAst { if(values == null) { values = new HashMap<>(); } } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.values.forEach((varAst, termAst) -> { + if(varAst != null) { + varAst.accept(visitor); + } + if(termAst != null) { + termAst.accept(visitor); + } + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValuesAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValuesAst.java index 323987aa2..64ca74019 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValuesAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/ValuesAst.java @@ -1,12 +1,15 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.VisitableAst; + import java.util.ArrayList; import java.util.List; /** * VALUES clause. Cumulated mappings of all the VALUES clauses declared in a query */ -public record ValuesAst(List mappings) { +public record ValuesAst(List mappings) implements VisitableAst { public ValuesAst { if(mappings == null) { @@ -17,4 +20,12 @@ public record ValuesAst(List mappings) { public static ValuesAst none() { return new ValuesAst(new ArrayList<>()); } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.mappings.forEach(valueMappingAst -> { + valueMappingAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/VarAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/VarAst.java index 5c98aab3b..77e603a12 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/VarAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/VarAst.java @@ -1,5 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * Variable in a triple pattern (e.g. ?s, $x). */ @@ -9,4 +11,14 @@ public record VarAst(String name) implements TermAst { throw new IllegalArgumentException("Variable name is null or blank"); } } + + @Override + public String getName() { + return this.name; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbsAst.java index 987450f90..9bed9cb71 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbsAst.java @@ -11,4 +11,9 @@ public class AbsAst extends AbstractUnaryConstraintAst implements NumericExpress public AbsAst(List args) { super(args); } + + @Override + public String getName() { + return "ABS"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryConstraintAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryConstraintAst.java index 50feed040..c4c84dc36 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryConstraintAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryConstraintAst.java @@ -2,6 +2,7 @@ import fr.inria.corese.core.next.query.api.exception.QueryEvaluationException; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import java.util.List; @@ -37,4 +38,11 @@ protected void setRightArgument(TermAst arg) { this.rightArgument = arg; } + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.leftArgument.accept(visitor); + this.rightArgument.accept(visitor); + } + } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryFunctionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryFunctionAst.java index 2bba28ca6..68565257c 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryFunctionAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractBinaryFunctionAst.java @@ -4,7 +4,7 @@ import java.util.List; -public class AbstractBinaryFunctionAst extends AbstractBinaryConstraintAst { +public abstract class AbstractBinaryFunctionAst extends AbstractBinaryConstraintAst { protected AbstractBinaryFunctionAst(List args) { super(args); this.setLeftArgument(args.getFirst()); diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnaryConstraintAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnaryConstraintAst.java index 6356da5e3..4a40c5848 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnaryConstraintAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnaryConstraintAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import java.util.List; @@ -8,7 +9,14 @@ public abstract class AbstractUnaryConstraintAst implements UnaryConstraintAst { private final TermAst argument; - protected AbstractUnaryConstraintAst(List args) { + public AbstractUnaryConstraintAst(TermAst arg) { + if (arg == null) { + throw new IllegalArgumentException("arg must be non-null"); + } + this.argument = arg; + } + + public AbstractUnaryConstraintAst(List args) { if(args.size() == 1) { this.argument = args.getFirst(); } else { @@ -16,7 +24,13 @@ protected AbstractUnaryConstraintAst(List args) { } } - public TermAst getArgument() { + public TermAst argument() { return this.argument; } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.argument.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnlimitedArgumentsFunctionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnlimitedArgumentsFunctionAst.java new file mode 100644 index 000000000..6b4d51ce9 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AbstractUnlimitedArgumentsFunctionAst.java @@ -0,0 +1,30 @@ +package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; + +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; +import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; + +import java.util.List; + +public abstract class AbstractUnlimitedArgumentsFunctionAst implements UnlimitedArgumentsFunctionAst { + + private final List arguments; + + protected AbstractUnlimitedArgumentsFunctionAst(List arguments) { + this.arguments = arguments != null ? List.copyOf(arguments) : List.of(); + } + + @Override + public List arguments() { + return arguments; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + for (TermAst termAst : arguments) { + if (termAst != null) { + termAst.accept(visitor); + } + } + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AddAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AddAst.java index 1b1d96716..a27025227 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AddAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AddAst.java @@ -18,4 +18,9 @@ public AddAst(List args) { protected TermAst create(List args) { return new AddAst(args); } + + @Override + public String getName() { + return "+"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AndAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AndAst.java index e2237e2ab..b00e2276d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AndAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/AndAst.java @@ -17,4 +17,9 @@ public AndAst(List args) { protected TermAst create(List args) { return new AndAst(args); } + + @Override + public String getName() { + return "&&"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BinaryRegexAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BinaryRegexAst.java index 1823ff40b..c906e694b 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BinaryRegexAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BinaryRegexAst.java @@ -31,4 +31,9 @@ public TermAst getString() { public TermAst getPattern() { return this.getRightArgument(); } + + @Override + public String getName() { + return "REGEX"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BnodeAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BnodeAst.java index fadab152b..c5c04d4f5 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BnodeAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BnodeAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ExprAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; @@ -23,4 +24,17 @@ public BnodeAst(List args) { public TermAst getLabel() { return this.label; } + + @Override + public String getName() { + return "BNODE"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + if(this.label != null) { + this.label.accept(visitor); + } + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BooleanNotAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BooleanNotAst.java index a4042ff37..ee2d09afa 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BooleanNotAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BooleanNotAst.java @@ -11,4 +11,9 @@ public class BooleanNotAst extends AbstractUnaryConstraintAst implements Boolean public BooleanNotAst(List arg) { super(arg); } + + @Override + public String getName() { + return "!"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BoundAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BoundAst.java index e81254ce2..b880434ee 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BoundAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/BoundAst.java @@ -13,4 +13,9 @@ public class BoundAst extends AbstractUnaryConstraintAst implements BooleanExpre public BoundAst(List args) { super(args); } + + @Override + public String getName() { + return "BOUND"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CeilAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CeilAst.java index caab8d4f6..48bae7d2e 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CeilAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CeilAst.java @@ -11,4 +11,9 @@ public class CeilAst extends AbstractUnaryConstraintAst implements NumericExpres public CeilAst(List args) { super(args); } + + @Override + public String getName() { + return "CEIL"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CoalesceAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CoalesceAst.java index 0a9539ff9..972e22c2d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CoalesceAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/CoalesceAst.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import java.util.List; @@ -8,4 +9,14 @@ * Function {@code COALESCE(expr1, expr2, ...)} in SPARQL 1.1 * Returns the first argument that evaluates without error. */ -public record CoalesceAst(List arguments) implements ConstraintAst {} \ No newline at end of file +public class CoalesceAst extends AbstractUnlimitedArgumentsFunctionAst { + + public CoalesceAst(List arguments) { + super(arguments); + } + + @Override + public String getName() { + return "COALESCE"; + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ConcatAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ConcatAst.java index 0c82ed408..cb7e62219 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ConcatAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ConcatAst.java @@ -7,4 +7,14 @@ /** * Function {@code CONCAT(expr1, expr2, ...)} in SPARQL 1.1. */ -public record ConcatAst(List arguments) implements SimpleLiteralExpressionAst {} +public class ConcatAst extends AbstractUnlimitedArgumentsFunctionAst implements SimpleLiteralExpressionAst { + + public ConcatAst(List arguments) { + super(arguments); + } + + @Override + public String getName() { + return "CONCAT"; + } +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ContainsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ContainsAst.java index d3d7ddc0a..19589d0db 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ContainsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ContainsAst.java @@ -13,4 +13,9 @@ public class ContainsAst extends AbstractBinaryFunctionAst implements BooleanExp public ContainsAst(List args) { super(args); } + + @Override + public String getName() { + return "CONTAINS"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DatatypeAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DatatypeAst.java index 60ae33a90..11ece3c52 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DatatypeAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DatatypeAst.java @@ -13,4 +13,9 @@ public class DatatypeAst extends AbstractUnaryConstraintAst implements IriExpres public DatatypeAst(List args) { super(args); } + + @Override + public String getName() { + return "DATATYPE"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DayAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DayAst.java index 6dea2e68a..6cc9e9ef0 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DayAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DayAst.java @@ -12,4 +12,9 @@ public class DayAst extends AbstractUnaryConstraintAst implements NumericExpress public DayAst(List args) { super(args); } + + @Override + public String getName() { + return "DAY"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DifferentAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DifferentAst.java index edce87e8f..1060356be 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DifferentAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DifferentAst.java @@ -18,4 +18,8 @@ protected TermAst create(List args) { return new DifferentAst(args); } + @Override + public String getName() { + return "!="; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DivideAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DivideAst.java index 8ff0e837c..17834e3e7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DivideAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/DivideAst.java @@ -17,4 +17,9 @@ public DivideAst(List args) { protected TermAst create(List args) { return new DivideAst(args); } + + @Override + public String getName() { + return "/"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EncodeForUriAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EncodeForUriAst.java index 22aa881f1..2fcb24108 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EncodeForUriAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EncodeForUriAst.java @@ -11,4 +11,9 @@ public class EncodeForUriAst extends AbstractUnaryConstraintAst implements Simpl public EncodeForUriAst(List args) { super(args); } + + @Override + public String getName() { + return "ENCODE_FOR_URI"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EqualsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EqualsAst.java index d5e32954e..3d6692e43 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EqualsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/EqualsAst.java @@ -17,4 +17,9 @@ public EqualsAst(List args) { protected TermAst create(List args) { return new EqualsAst(args); } + + @Override + public String getName() { + return "="; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ExistsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ExistsAst.java index 69d79c83b..4f581d375 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ExistsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ExistsAst.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.GroupGraphPatternAst; import java.util.Objects; @@ -13,4 +14,15 @@ public record ExistsAst(GroupGraphPatternAst pattern) implements BooleanExpressi public ExistsAst { Objects.requireNonNull(pattern, "pattern"); } + + @Override + public String getName() { + return "EXISTS"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.pattern.accept(visitor); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FloorAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FloorAst.java index 62559acbd..6015c287f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FloorAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FloorAst.java @@ -11,4 +11,9 @@ public class FloorAst extends AbstractUnaryConstraintAst implements NumericExpre public FloorAst(List args) { super(args); } + + @Override + public String getName() { + return "FLOOR"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FunctionCallAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FunctionCallAst.java index 410c5cde2..e12db4e4b 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FunctionCallAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/FunctionCallAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ExprAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; @@ -17,4 +18,18 @@ public record FunctionCallAst(TermAst functionName, List arguments) imp } } + + @Override + public String getName() { + return "Function call " + functionName.getName(); + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.functionName.accept(visitor); + this.arguments.forEach(termAst -> { + termAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterOrEqualThanAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterOrEqualThanAst.java index e2f0d2574..d3babb19b 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterOrEqualThanAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterOrEqualThanAst.java @@ -17,4 +17,9 @@ public GreaterOrEqualThanAst(List args) { protected TermAst create(List args) { return new GreaterOrEqualThanAst(args); } + + @Override + public String getName() { + return ">="; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterThanAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterThanAst.java index 1a937c8e3..bebed9cf2 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterThanAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/GreaterThanAst.java @@ -17,4 +17,9 @@ public GreaterThanAst(List args) { protected TermAst create(List args) { return new GreaterThanAst(args); } + + @Override + public String getName() { + return ">"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/HoursAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/HoursAst.java index b1b0a3ea6..47229e74e 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/HoursAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/HoursAst.java @@ -12,4 +12,9 @@ public class HoursAst extends AbstractUnaryConstraintAst implements NumericExpre public HoursAst(List args) { super(args); } + + @Override + public String getName() { + return "HOURS"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IfAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IfAst.java index 3e3718271..a779916ef 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IfAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IfAst.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; @@ -7,4 +8,18 @@ * Function {@code IF(condition, thenExpr, elseExpr)} in SPARQL 1.1 * Evaluates condition; if true returns thenExpr, otherwise elseExpr. */ -public record IfAst(TermAst condition, TermAst thenExpr, TermAst elseExpr) implements ConstraintAst {} \ No newline at end of file +public record IfAst(TermAst condition, TermAst thenExpr, TermAst elseExpr) implements ConstraintAst { + + @Override + public String getName() { + return "IF"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.condition.accept(visitor); + this.thenExpr.accept(visitor); + this.elseExpr.accept(visitor); + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/InAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/InAst.java index 83daece4a..0e693b46a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/InAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/InAst.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; @@ -16,4 +17,18 @@ public record InAst(TermAst left, List candidates) implements Constrain Objects.requireNonNull(candidates, "candidates"); candidates = List.copyOf(candidates); } + + @Override + public String getName() { + return "IN"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.left.accept(visitor); + this.candidates.forEach(termAst -> { + termAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IriFunctionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IriFunctionAst.java index 970f37cf1..cacc519ef 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IriFunctionAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IriFunctionAst.java @@ -11,4 +11,9 @@ public class IriFunctionAst extends AbstractUnaryConstraintAst implements IriExp public IriFunctionAst(List args) { super(args); } + + @Override + public String getName() { + return "IRI"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsBlankAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsBlankAst.java index e9050aaa7..63bc6636a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsBlankAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsBlankAst.java @@ -12,4 +12,9 @@ public class IsBlankAst extends AbstractUnaryConstraintAst implements BooleanExp public IsBlankAst(List args) { super(args); } + + @Override + public String getName() { + return "ISBLANK"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsIriAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsIriAst.java index 9f814aa29..5f9602f60 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsIriAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsIriAst.java @@ -12,4 +12,9 @@ public class IsIriAst extends AbstractUnaryConstraintAst implements BooleanExpre public IsIriAst(List args) { super(args); } + + @Override + public String getName() { + return "ISIRI"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsLiteralAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsLiteralAst.java index 37b3904f5..97ceb6411 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsLiteralAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/IsLiteralAst.java @@ -12,4 +12,9 @@ public class IsLiteralAst extends AbstractUnaryConstraintAst implements BooleanE public IsLiteralAst(List args) { super(args); } + + @Override + public String getName() { + return "ISLITERAL"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangAst.java index 23c2eaae2..d77fe90b4 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangAst.java @@ -13,4 +13,9 @@ public class LangAst extends AbstractUnaryConstraintAst implements SimpleLiteral public LangAst(List args) { super(args); } + + @Override + public String getName() { + return "LANG"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangMatchesAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangMatchesAst.java index bc6e29330..8e6da0bca 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangMatchesAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LangMatchesAst.java @@ -14,4 +14,9 @@ public class LangMatchesAst extends AbstractBinaryFunctionAst implements Boolean public LangMatchesAst(List args) { super(args); } + + @Override + public String getName() { + return "LANGMATCHES"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LcaseAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LcaseAst.java index 4e62100ee..f370d6e32 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LcaseAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LcaseAst.java @@ -11,4 +11,9 @@ public class LcaseAst extends AbstractUnaryConstraintAst implements SimpleLitera public LcaseAst(List args) { super(args); } + + @Override + public String getName() { + return "LCASE"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerOrEqualThanAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerOrEqualThanAst.java index aadcc17cc..09aaa3bf7 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerOrEqualThanAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerOrEqualThanAst.java @@ -17,4 +17,9 @@ public LowerOrEqualThanAst(List args) { protected TermAst create(List args) { return new LowerOrEqualThanAst(args); } + + @Override + public String getName() { + return "<="; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerThanAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerThanAst.java index 61322e80a..0577d0896 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerThanAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/LowerThanAst.java @@ -17,4 +17,9 @@ public LowerThanAst(List args) { protected TermAst create(List args) { return new LowerThanAst(args); } + + @Override + public String getName() { + return "<"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Md5Ast.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Md5Ast.java index d10626b58..a93a3b449 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Md5Ast.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Md5Ast.java @@ -11,4 +11,9 @@ public class Md5Ast extends AbstractUnaryConstraintAst implements SimpleLiteralE public Md5Ast(List args) { super(args); } + + @Override + public String getName() { + return "MD5"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MinutesAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MinutesAst.java index b68a7f7da..48ce390ca 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MinutesAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MinutesAst.java @@ -12,4 +12,9 @@ public class MinutesAst extends AbstractUnaryConstraintAst implements NumericExp public MinutesAst(List args) { super(args); } + + @Override + public String getName() { + return "MINUTES"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MonthAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MonthAst.java index 329e14a84..f38a11653 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MonthAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MonthAst.java @@ -12,4 +12,9 @@ public class MonthAst extends AbstractUnaryConstraintAst implements NumericExpre public MonthAst(List args) { super(args); } + + @Override + public String getName() { + return "MONTH"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MultiplyAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MultiplyAst.java index 2d03d5885..a706c7a5d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MultiplyAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/MultiplyAst.java @@ -17,4 +17,9 @@ public MultiplyAst(List args) { protected TermAst create(List args) { return new MultiplyAst(args); } + + @Override + public String getName() { + return "*"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotExistsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotExistsAst.java index 490a9c58c..653a1e80a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotExistsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotExistsAst.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.GroupGraphPatternAst; import java.util.Objects; @@ -13,4 +14,15 @@ public record NotExistsAst(GroupGraphPatternAst pattern) implements BooleanExpre public NotExistsAst { Objects.requireNonNull(pattern, "pattern"); } + + @Override + public String getName() { + return "NOT EXISTS"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.pattern.accept(visitor); + } } \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotInAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotInAst.java index 4e1ddb437..a116325f3 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotInAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NotInAst.java @@ -1,5 +1,6 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; @@ -16,4 +17,18 @@ public record NotInAst(TermAst left, List candidates) implements Constr Objects.requireNonNull(candidates, "candidates"); candidates = List.copyOf(candidates); } + + @Override + public String getName() { + return "NOT IN"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.left.accept(visitor); + this.candidates.forEach(termAst -> { + termAst.accept(visitor); + }); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NowAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NowAst.java index 9b374a62b..c6b4640e2 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NowAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/NowAst.java @@ -1,9 +1,21 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * Function {@code NOW()} in SPARQL 1.1 — §17.4.5.1. * Returns the current query execution time as an {@code xsd:dateTime}. * This function takes no arguments. */ public class NowAst implements XsdDateTimeExpressionAst { + + @Override + public String getName() { + return "NOW"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/OrAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/OrAst.java index 589de76f4..9334e13a6 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/OrAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/OrAst.java @@ -16,4 +16,9 @@ public OrAst(List args) { protected TermAst create(List args) { return new OrAst(args); } + + @Override + public String getName() { + return "||"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RandAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RandAst.java index 8e2e9538d..8e87aff02 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RandAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RandAst.java @@ -1,7 +1,19 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; + /** * Function {@code RAND()} in SPARQL 1.1. */ public record RandAst() implements NumericExpressionAst { + + @Override + public String getName() { + return "RAND"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ReplaceAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ReplaceAst.java index e3801fbca..f63bda77f 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ReplaceAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/ReplaceAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import java.util.List; @@ -51,4 +52,20 @@ public TermAst getFlags() { public boolean hasFlags() { return flagsArg != null; } + + @Override + public String getName() { + return "REPLACE"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.stringArg.accept(visitor); + this.patternArg.accept(visitor); + this.replacementArg.accept(visitor); + if(flagsArg != null) { + this.flagsArg.accept(visitor); + } + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RoundAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RoundAst.java index 13277e940..2dc55519e 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RoundAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/RoundAst.java @@ -11,4 +11,9 @@ public class RoundAst extends AbstractUnaryConstraintAst implements NumericExpre public RoundAst(List args) { super(args); } + + @Override + public String getName() { + return "ROUND"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SameTermAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SameTermAst.java index 8663ebd02..0285195ba 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SameTermAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SameTermAst.java @@ -20,4 +20,9 @@ public SameTermAst(List args) { throw new QuerySyntaxException("Unexpected number of arguments for sameTerm function"); } } + + @Override + public String getName() { + return "SAMETERM"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SecondsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SecondsAst.java index 57c84d34d..a2731a269 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SecondsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SecondsAst.java @@ -12,4 +12,9 @@ public class SecondsAst extends AbstractUnaryConstraintAst implements NumericExp public SecondsAst(List args) { super(args); } + + @Override + public String getName() { + return "SECONDS"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha1Ast.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha1Ast.java index 1cb1c7bf4..349acde11 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha1Ast.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha1Ast.java @@ -11,4 +11,9 @@ public class Sha1Ast extends AbstractUnaryConstraintAst implements SimpleLiteral public Sha1Ast(List args) { super(args); } + + @Override + public String getName() { + return "SHA1"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha256Ast.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha256Ast.java index 9b088ec77..6d5bcb647 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha256Ast.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha256Ast.java @@ -11,4 +11,9 @@ public class Sha256Ast extends AbstractUnaryConstraintAst implements SimpleLiter public Sha256Ast(List args) { super(args); } + + @Override + public String getName() { + return "SHA256"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha384Ast.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha384Ast.java index a94d07c92..efeead2a3 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha384Ast.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha384Ast.java @@ -11,4 +11,9 @@ public class Sha384Ast extends AbstractUnaryConstraintAst implements SimpleLiter public Sha384Ast(List args) { super(args); } + + @Override + public String getName() { + return "SHA384"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha512Ast.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha512Ast.java index 3c0a920c8..0b6f7b274 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha512Ast.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/Sha512Ast.java @@ -11,4 +11,9 @@ public class Sha512Ast extends AbstractUnaryConstraintAst implements SimpleLiter public Sha512Ast(List args) { super(args); } + + @Override + public String getName() { + return "SHA512"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAfterAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAfterAst.java index 885d99d35..5fa2b485a 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAfterAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAfterAst.java @@ -13,4 +13,9 @@ public class StrAfterAst extends AbstractBinaryFunctionAst implements SimpleLite public StrAfterAst(List args) { super(args); } + + @Override + public String getName() { + return "STRAFTER"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAst.java index 69a7a9ec2..53ae66791 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrAst.java @@ -13,4 +13,9 @@ public class StrAst extends AbstractUnaryConstraintAst implements SimpleLiteralE public StrAst(List args) { super(args); } + + @Override + public String getName() { + return "STR"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrBeforeAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrBeforeAst.java index 91ad3efb6..beb398dba 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrBeforeAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrBeforeAst.java @@ -13,4 +13,9 @@ public class StrBeforeAst extends AbstractBinaryFunctionAst implements SimpleLit public StrBeforeAst(List args) { super(args); } + + @Override + public String getName() { + return "STRBEFORE"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrDtAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrDtAst.java index f9e9be3ab..5346304ea 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrDtAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrDtAst.java @@ -12,4 +12,9 @@ public class StrDtAst extends AbstractBinaryFunctionAst implements LiteralExpres public StrDtAst(List args) { super(args); } + + @Override + public String getName() { + return "STRDT"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrEndsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrEndsAst.java index 5f7dc54b0..335d7979e 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrEndsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrEndsAst.java @@ -13,4 +13,9 @@ public class StrEndsAst extends AbstractBinaryFunctionAst implements BooleanExpr public StrEndsAst(List args) { super(args); } + + @Override + public String getName() { + return "STRENDS"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLangAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLangAst.java index 01d54a577..7bb0867d2 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLangAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLangAst.java @@ -12,4 +12,9 @@ public class StrLangAst extends AbstractBinaryFunctionAst implements SimpleLiter public StrLangAst(List args) { super(args); } + + @Override + public String getName() { + return "STRLANG"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLenAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLenAst.java index 36a52b00d..e0647fbe0 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLenAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrLenAst.java @@ -3,8 +3,24 @@ import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; +import java.util.List; + /** * Function {@code STRLEN(string)} in SPARQL 1.1 * Returns the length of a string. */ -public record StrLenAst(TermAst argument) implements ConstraintAst {} \ No newline at end of file +public class StrLenAst extends AbstractUnaryConstraintAst implements NumericExpressionAst { + + public StrLenAst(TermAst arg) { + super(arg); + } + + public StrLenAst(List args) { + super(args); + } + + @Override + public String getName() { + return "STRLEN"; + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrStartsAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrStartsAst.java index aae07b0b9..23ec4fc68 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrStartsAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrStartsAst.java @@ -13,4 +13,9 @@ public class StrStartsAst extends AbstractBinaryFunctionAst implements BooleanEx public StrStartsAst(List args) { super(args); } + + @Override + public String getName() { + return "STRSTARTS"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrUuidAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrUuidAst.java index 7012a179c..a5fd07e3d 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrUuidAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/StrUuidAst.java @@ -1,9 +1,21 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; /** * Function {@code STRUUID()} in SPARQL 1.1 * Returns a string form of a UUID. */ -public record StrUuidAst() implements ConstraintAst {} \ No newline at end of file +public record StrUuidAst() implements ConstraintAst { + + @Override + public String getName() { + return "STRUUID"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubstrAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubstrAst.java index 01b22cd7d..8e9264267 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubstrAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubstrAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import java.util.List; @@ -35,4 +36,19 @@ public TermAst getStart() { public TermAst getLength() { return this.lengthArg; } + + @Override + public String getName() { + return "SUBSTR"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.stringArg.accept(visitor); + this.startArg.accept(visitor); + if(this.lengthArg != null) { + this.lengthArg.accept(visitor); + } + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubtractAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubtractAst.java index 01e08ffb6..cbc0bed62 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubtractAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/SubtractAst.java @@ -18,4 +18,9 @@ public SubtractAst(List args) { protected TermAst create(List args) { return new SubtractAst(args); } + + @Override + public String getName() { + return "-"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TimezoneAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TimezoneAst.java index daaa5ba53..d2f5e03bb 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TimezoneAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TimezoneAst.java @@ -13,4 +13,9 @@ public class TimezoneAst extends AbstractUnaryConstraintAst implements XsdDayTim public TimezoneAst(List args) { super(args); } + + @Override + public String getName() { + return "TIMEZONE"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TrinaryRegexAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TrinaryRegexAst.java index 9fb205374..0cfc7aeab 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TrinaryRegexAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TrinaryRegexAst.java @@ -1,6 +1,7 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; import fr.inria.corese.core.next.query.api.exception.QuerySyntaxException; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; import java.util.List; @@ -39,4 +40,17 @@ public TermAst getPattern() { public TermAst getFlags() { return this.flags; } + + @Override + public String getName() { + return "REGEX"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + this.stringArg.accept(visitor); + this.patternArg.accept(visitor); + this.flags.accept(visitor); + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TzAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TzAst.java index d2a8766ed..c435472f4 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TzAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/TzAst.java @@ -13,4 +13,9 @@ public class TzAst extends AbstractUnaryConstraintAst implements SimpleLiteralEx public TzAst(List args) { super(args); } + + @Override + public String getName() { + return "TZ"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UcaseAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UcaseAst.java index 9a9fe39d1..ea79d7fad 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UcaseAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UcaseAst.java @@ -11,4 +11,9 @@ public class UcaseAst extends AbstractUnaryConstraintAst implements SimpleLitera public UcaseAst(List args) { super(args); } + + @Override + public String getName() { + return "UCASE"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryConstraintAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryConstraintAst.java index 6020c99c0..3dceb1554 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryConstraintAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryConstraintAst.java @@ -7,5 +7,5 @@ * Interface for AST elements using one term as argument */ public interface UnaryConstraintAst extends ConstraintAst { - TermAst getArgument(); + TermAst argument(); } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryMinusAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryMinusAst.java index ed4be4016..508fc5771 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryMinusAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryMinusAst.java @@ -11,4 +11,9 @@ public class UnaryMinusAst extends AbstractUnaryConstraintAst implements Numeric public UnaryMinusAst(List args) { super(args); } + + @Override + public String getName() { + return "-"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryPlusAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryPlusAst.java index 316577ac6..c2de16f00 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryPlusAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnaryPlusAst.java @@ -11,4 +11,9 @@ public class UnaryPlusAst extends AbstractUnaryConstraintAst implements NumericE public UnaryPlusAst(List args) { super(args); } + + @Override + public String getName() { + return "+"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnlimitedArgumentsFunctionAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnlimitedArgumentsFunctionAst.java new file mode 100644 index 000000000..bb3b66f84 --- /dev/null +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UnlimitedArgumentsFunctionAst.java @@ -0,0 +1,10 @@ +package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; + +import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst; + +import java.util.List; + +public interface UnlimitedArgumentsFunctionAst extends ConstraintAst { + List arguments(); +} diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UuidAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UuidAst.java index 1fe2e5644..9d9e6b6a5 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UuidAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/UuidAst.java @@ -1,9 +1,21 @@ package fr.inria.corese.core.next.query.impl.sparql.ast.constraint; +import fr.inria.corese.core.next.query.impl.parser.semantic.support.AstVisitor; import fr.inria.corese.core.next.query.impl.sparql.ast.ConstraintAst; /** * Function {@code UUID()} in SPARQL 1.1 * Returns a fresh IRI from the UUID URN scheme. */ -public record UuidAst() implements ConstraintAst {} \ No newline at end of file +public record UuidAst() implements ConstraintAst { + + @Override + public String getName() { + return "UUID"; + } + + @Override + public void accept(AstVisitor visitor) { + visitor.visit(this); + } +} \ No newline at end of file diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/YearAst.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/YearAst.java index c61d30221..b90bdf982 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/YearAst.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/ast/constraint/YearAst.java @@ -12,4 +12,9 @@ public class YearAst extends AbstractUnaryConstraintAst implements NumericExpres public YearAst(List args) { super(args); } + + @Override + public String getName() { + return "YEAR"; + } } diff --git a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java index 6a2079997..91ed53006 100644 --- a/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java +++ b/src/main/java/fr/inria/corese/core/next/query/impl/sparql/bridge/SparqlAstToExpression.java @@ -127,25 +127,25 @@ private static Expression constraintToExpression(ConstraintAst constraint) { case DivideAst divideAst -> Term.create("/", convert(divideAst.getLeftArgument()), convert(divideAst.getRightArgument())); case UnaryPlusAst unaryPlusAst -> - Term.create("+", convert(unaryPlusAst.getArgument())); + Term.create("+", convert(unaryPlusAst.argument())); case UnaryMinusAst unaryMinusAst -> - Term.create("-", convert(unaryMinusAst.getArgument())); + Term.create("-", convert(unaryMinusAst.argument())); case BooleanNotAst booleanNotAst -> - Term.create("!", convert(booleanNotAst.getArgument())); + Term.create("!", convert(booleanNotAst.argument())); case BoundAst boundAst -> - functionTerm(Processor.BOUND, convert(boundAst.getArgument())); + functionTerm(Processor.BOUND, convert(boundAst.argument())); case IsIriAst isIriAst -> - functionTerm("isIRI", convert(isIriAst.getArgument())); + functionTerm("isIRI", convert(isIriAst.argument())); case IsBlankAst isBlankAst -> - functionTerm("isBlank", convert(isBlankAst.getArgument())); + functionTerm("isBlank", convert(isBlankAst.argument())); case IsLiteralAst isLiteralAst -> - functionTerm("isLiteral", convert(isLiteralAst.getArgument())); + functionTerm("isLiteral", convert(isLiteralAst.argument())); case StrAst strAst -> - functionTerm("str", convert(strAst.getArgument())); + functionTerm("str", convert(strAst.argument())); case LangAst langAst -> - functionTerm("lang", convert(langAst.getArgument())); + functionTerm("lang", convert(langAst.argument())); case DatatypeAst datatypeAst -> - functionTerm("datatype", convert(datatypeAst.getArgument())); + functionTerm("datatype", convert(datatypeAst.argument())); case SameTermAst sameTermAst -> functionTerm("sameTerm", convert(sameTermAst.getLeftArgument()), convert(sameTermAst.getRightArgument())); case LangMatchesAst langMatchesAst -> @@ -183,23 +183,23 @@ private static Expression constraintToExpression(ConstraintAst constraint) { case StrDtAst strDtAst -> functionTerm(Processor.STRDT, convert(strDtAst.getLeftArgument()), convert(strDtAst.getRightArgument())); case IriFunctionAst iriFunctionAst -> - functionTerm("iri", convert(iriFunctionAst.getArgument())); + functionTerm("iri", convert(iriFunctionAst.argument())); case LcaseAst lcaseAst -> - functionTerm("lcase", convert(lcaseAst.getArgument())); + functionTerm("lcase", convert(lcaseAst.argument())); case UcaseAst ucaseAst -> - functionTerm("ucase", convert(ucaseAst.getArgument())); + functionTerm("ucase", convert(ucaseAst.argument())); case EncodeForUriAst encodeForUriAst -> - functionTerm("encode_for_uri", convert(encodeForUriAst.getArgument())); + functionTerm("encode_for_uri", convert(encodeForUriAst.argument())); case Md5Ast md5Ast -> - functionTerm("md5", convert(md5Ast.getArgument())); + functionTerm("md5", convert(md5Ast.argument())); case Sha1Ast sha1Ast -> - functionTerm("sha1", convert(sha1Ast.getArgument())); + functionTerm("sha1", convert(sha1Ast.argument())); case Sha256Ast sha256Ast -> - functionTerm("sha256", convert(sha256Ast.getArgument())); + functionTerm("sha256", convert(sha256Ast.argument())); case Sha384Ast sha384Ast -> - functionTerm("sha384", convert(sha384Ast.getArgument())); + functionTerm("sha384", convert(sha384Ast.argument())); case Sha512Ast sha512Ast -> - functionTerm("sha512", convert(sha512Ast.getArgument())); + functionTerm("sha512", convert(sha512Ast.argument())); case ExistsAst existsAst -> throw new UnsupportedOperationException( "EXISTS { ... } conversion requires GroupGraphPatternAst → Exp (see CoreseAstQueryBuilder)"); diff --git a/src/main/java/fr/inria/corese/core/sparql/triple/api/ASTVisitable.java b/src/main/java/fr/inria/corese/core/sparql/triple/api/AstVisitable.java similarity index 87% rename from src/main/java/fr/inria/corese/core/sparql/triple/api/ASTVisitable.java rename to src/main/java/fr/inria/corese/core/sparql/triple/api/AstVisitable.java index cea5b87c4..a586d5e70 100644 --- a/src/main/java/fr/inria/corese/core/sparql/triple/api/ASTVisitable.java +++ b/src/main/java/fr/inria/corese/core/sparql/triple/api/AstVisitable.java @@ -8,7 +8,7 @@ * * @author corby */ -public interface ASTVisitable { +public interface AstVisitable { void accept(ASTVisitor visitor); diff --git a/src/main/java/fr/inria/corese/core/sparql/triple/parser/ASTQuery.java b/src/main/java/fr/inria/corese/core/sparql/triple/parser/ASTQuery.java index 022f2c1d5..9ce2f021f 100755 --- a/src/main/java/fr/inria/corese/core/sparql/triple/parser/ASTQuery.java +++ b/src/main/java/fr/inria/corese/core/sparql/triple/parser/ASTQuery.java @@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory; import fr.inria.corese.core.sparql.datatype.DatatypeMap; -import fr.inria.corese.core.sparql.triple.api.ASTVisitable; +import fr.inria.corese.core.sparql.triple.api.AstVisitable; import fr.inria.corese.core.sparql.triple.api.ASTVisitor; import fr.inria.corese.core.sparql.triple.cst.Keyword; import fr.inria.corese.core.sparql.triple.cst.KeywordPP; @@ -48,7 +48,7 @@ */ public class ASTQuery extends ASTObject - implements Keyword, ASTVisitable, AST, Message { + implements Keyword, AstVisitable, AST, Message { public static boolean STRICT_MODE; diff --git a/src/main/java/fr/inria/corese/core/sparql/triple/parser/TopExp.java b/src/main/java/fr/inria/corese/core/sparql/triple/parser/TopExp.java index cdbf14e92..7385f89f9 100755 --- a/src/main/java/fr/inria/corese/core/sparql/triple/parser/TopExp.java +++ b/src/main/java/fr/inria/corese/core/sparql/triple/parser/TopExp.java @@ -1,6 +1,6 @@ package fr.inria.corese.core.sparql.triple.parser; -import fr.inria.corese.core.sparql.triple.api.ASTVisitable; +import fr.inria.corese.core.sparql.triple.api.AstVisitable; import fr.inria.corese.core.sparql.triple.api.ASTVisitor; import java.util.ArrayList; import java.util.List; @@ -11,7 +11,7 @@ * @author corby * */ -public class TopExp implements ASTVisitable { +public class TopExp implements AstVisitable { public boolean isGenerated() { return generated; diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserAggregateTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserAggregateTest.java index 18e5eddcf..6a9d88f26 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserAggregateTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserAggregateTest.java @@ -18,6 +18,9 @@ @DisplayName("SPARQL 1.1 — Parser and AST : aggregates") class SparqlParserAggregateTest extends AbstractSparqlParserFeatureTest { + /** + * gets the last Pattern of the where clause, assuming it is an Aggregate + */ private static AggregateAst lastBindAggregate(WhereClauseQueryAst ast) { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); return assertInstanceOf(AggregateAst.class, bind.expression()); diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserBnodeTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserBnodeTest.java index 0c41ea9f1..c28a1e071 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserBnodeTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserBnodeTest.java @@ -70,7 +70,7 @@ void shouldParseNestedBnodeInIsBlankFilter() { assertNotNull(ast); FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); IsBlankAst isBlank = assertInstanceOf(IsBlankAst.class, filter.operator()); - BnodeAst bnode = assertInstanceOf(BnodeAst.class, isBlank.getArgument()); + BnodeAst bnode = assertInstanceOf(BnodeAst.class, isBlank.argument()); assertEquals("label", assertInstanceOf(VarAst.class, bnode.getLabel()).name()); } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserCoalesceTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserCoalesceTest.java index d549bc052..c73dafea6 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserCoalesceTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserCoalesceTest.java @@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import fr.inria.corese.core.next.query.impl.sparql.ast.*; +import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.EqualsAst; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -24,15 +25,16 @@ void shouldParseCoalesceWithThreeArgs() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(COALESCE(?s, ?p, ?o)) + FILTER(COALESCE(?s, ?p, ?o) = "") } """); assertNotNull(ast); FilterAst filter = (FilterAst) ast.whereClause().patterns().getLast(); - assertInstanceOf(CoalesceAst.class, filter.operator()); - - CoalesceAst coalesce = (CoalesceAst) filter.operator(); + assertInstanceOf(EqualsAst.class, filter.operator()); + EqualsAst equalsAst = (EqualsAst) filter.operator(); + assertInstanceOf(CoalesceAst.class, equalsAst.getLeftArgument()); + CoalesceAst coalesce = (CoalesceAst) equalsAst.getLeftArgument(); assertEquals(3, coalesce.arguments().size()); assertInstanceOf(VarAst.class, coalesce.arguments().get(0)); assertInstanceOf(VarAst.class, coalesce.arguments().get(1)); @@ -73,15 +75,16 @@ void shouldParseCoalesceWithOneArg() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(COALESCE(?s)) + FILTER(COALESCE(?s) = 1) } """); assertNotNull(ast); FilterAst filter = (FilterAst) ast.whereClause().patterns().getLast(); - assertInstanceOf(CoalesceAst.class, filter.operator()); - - CoalesceAst coalesce = (CoalesceAst) filter.operator(); + assertInstanceOf(EqualsAst.class, filter.operator()); + EqualsAst equalsAst = (EqualsAst) filter.operator(); + assertInstanceOf(CoalesceAst.class, equalsAst.getLeftArgument()); + CoalesceAst coalesce = (CoalesceAst) equalsAst.getLeftArgument(); assertEquals(1, coalesce.arguments().size()); } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDateTimeFunctionsTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDateTimeFunctionsTest.java index f41707429..c87d2a20c 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDateTimeFunctionsTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserDateTimeFunctionsTest.java @@ -83,7 +83,7 @@ void shouldParseYearInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); YearAst year = assertInstanceOf(YearAst.class, bind.expression()); assertInstanceOf(NumericExpressionAst.class, year); - assertEquals("date", assertInstanceOf(VarAst.class, year.getArgument()).name()); + assertEquals("date", assertInstanceOf(VarAst.class, year.argument()).name()); } @Test @@ -135,7 +135,7 @@ void shouldParseMonthInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); MonthAst month = assertInstanceOf(MonthAst.class, bind.expression()); assertInstanceOf(NumericExpressionAst.class, month); - assertEquals("date", assertInstanceOf(VarAst.class, month.getArgument()).name()); + assertEquals("date", assertInstanceOf(VarAst.class, month.argument()).name()); } // ── DAY() ──────────────────────────────────────────────────────────────── @@ -156,7 +156,7 @@ void shouldParseDayInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); DayAst day = assertInstanceOf(DayAst.class, bind.expression()); assertInstanceOf(NumericExpressionAst.class, day); - assertEquals("date", assertInstanceOf(VarAst.class, day.getArgument()).name()); + assertEquals("date", assertInstanceOf(VarAst.class, day.argument()).name()); } // ── HOURS() ────────────────────────────────────────────────────────────── @@ -177,7 +177,7 @@ void shouldParseHoursInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); HoursAst hours = assertInstanceOf(HoursAst.class, bind.expression()); assertInstanceOf(NumericExpressionAst.class, hours); - assertEquals("dt", assertInstanceOf(VarAst.class, hours.getArgument()).name()); + assertEquals("dt", assertInstanceOf(VarAst.class, hours.argument()).name()); } // ── MINUTES() ──────────────────────────────────────────────────────────── @@ -198,7 +198,7 @@ void shouldParseMinutesInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); MinutesAst minutes = assertInstanceOf(MinutesAst.class, bind.expression()); assertInstanceOf(NumericExpressionAst.class, minutes); - assertEquals("dt", assertInstanceOf(VarAst.class, minutes.getArgument()).name()); + assertEquals("dt", assertInstanceOf(VarAst.class, minutes.argument()).name()); } // ── SECONDS() ──────────────────────────────────────────────────────────── @@ -219,7 +219,7 @@ void shouldParseSecondsInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); SecondsAst seconds = assertInstanceOf(SecondsAst.class, bind.expression()); assertInstanceOf(NumericExpressionAst.class, seconds); - assertEquals("dt", assertInstanceOf(VarAst.class, seconds.getArgument()).name()); + assertEquals("dt", assertInstanceOf(VarAst.class, seconds.argument()).name()); } // ── TIMEZONE() ─────────────────────────────────────────────────────────── @@ -240,7 +240,7 @@ void shouldParseTimezoneInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); TimezoneAst timezone = assertInstanceOf(TimezoneAst.class, bind.expression()); assertInstanceOf(XsdDayTimeDurationExpressionAst.class, timezone); - assertEquals("dt", assertInstanceOf(VarAst.class, timezone.getArgument()).name()); + assertEquals("dt", assertInstanceOf(VarAst.class, timezone.argument()).name()); } // ── TZ() ───────────────────────────────────────────────────────────────── @@ -261,7 +261,7 @@ void shouldParseTzInBind() { BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); TzAst tz = assertInstanceOf(TzAst.class, bind.expression()); assertInstanceOf(SimpleLiteralExpressionAst.class, tz); - assertEquals("dt", assertInstanceOf(VarAst.class, tz.getArgument()).name()); + assertEquals("dt", assertInstanceOf(VarAst.class, tz.argument()).name()); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserEncodeForUriTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserEncodeForUriTest.java index 976d977bd..958b74a99 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserEncodeForUriTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserEncodeForUriTest.java @@ -31,7 +31,7 @@ void shouldParseEncodeForUriInBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); EncodeForUriAst encode = assertInstanceOf(EncodeForUriAst.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, encode.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, encode.argument()).name()); assertEquals("encoded", bind.variable().name()); } @@ -50,7 +50,7 @@ void shouldParseEncodeForUriWithLiteralArgument() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); EncodeForUriAst encode = assertInstanceOf(EncodeForUriAst.class, bind.expression()); - LiteralAst literal = assertInstanceOf(LiteralAst.class, encode.getArgument()); + LiteralAst literal = assertInstanceOf(LiteralAst.class, encode.argument()); assertEquals("\"Los Angeles\"", literal.lexical()); assertEquals("encoded", bind.variable().name()); } @@ -71,7 +71,7 @@ void shouldParseEncodeForUriInFilterComparison() { FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); EqualsAst equals = assertInstanceOf(EqualsAst.class, filter.operator()); EncodeForUriAst encode = assertInstanceOf(EncodeForUriAst.class, equals.getLeftArgument()); - assertEquals("label", assertInstanceOf(VarAst.class, encode.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, encode.argument()).name()); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserFilterTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserFilterTest.java index bfb7d0496..59c18b66c 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserFilterTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserFilterTest.java @@ -155,9 +155,9 @@ void shouldParseNotFilter() { BooleanNotAst t = (BooleanNotAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -185,9 +185,9 @@ void shouldParseBoundFilter() { BoundAst t = (BoundAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -215,9 +215,9 @@ void shouldParseIsIriFilter() { IsIriAst t = (IsIriAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -245,9 +245,9 @@ void shouldParseIsUriFilter() { IsIriAst t = (IsIriAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -275,9 +275,9 @@ void shouldParseIsBlankFilter() { IsBlankAst t = (IsBlankAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -305,9 +305,9 @@ void shouldParseIsLiteralFilter() { IsLiteralAst t = (IsLiteralAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -340,8 +340,8 @@ void shouldParseStrEqualsFilter() { StrAst strAst = (StrAst) t.getLeftArgument(); - assertInstanceOf(VarAst.class, strAst.getArgument()); - assertEquals("s", ((VarAst) strAst.getArgument()).name()); + assertInstanceOf(VarAst.class, strAst.argument()); + assertEquals("s", ((VarAst) strAst.argument()).name()); } @Test @@ -374,8 +374,8 @@ void shouldParseLangEqualsFilter() { LangAst strAst = (LangAst) t.getLeftArgument(); - assertInstanceOf(VarAst.class, strAst.getArgument()); - assertEquals("s", ((VarAst) strAst.getArgument()).name()); + assertInstanceOf(VarAst.class, strAst.argument()); + assertEquals("s", ((VarAst) strAst.argument()).name()); } @Test @@ -408,8 +408,8 @@ void shouldParseDatatypeEqualsFilter() { DatatypeAst strAst = (DatatypeAst) t.getLeftArgument(); - assertInstanceOf(VarAst.class, strAst.getArgument()); - assertEquals("s", ((VarAst) strAst.getArgument()).name()); + assertInstanceOf(VarAst.class, strAst.argument()); + assertEquals("s", ((VarAst) strAst.argument()).name()); } @Test @@ -483,7 +483,7 @@ void shouldParseLowerFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(?s < ) + FILTER(?s < 2) } """); @@ -501,11 +501,11 @@ void shouldParseLowerFilter() { LowerThanAst t = (LowerThanAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getLeftArgument()); - assertInstanceOf(IriAst.class, t.getRightArgument()); + VarAst varAst = assertInstanceOf(VarAst.class, t.getLeftArgument()); + LiteralAst literalAst = assertInstanceOf(LiteralAst.class, t.getRightArgument()); - assertEquals("s", ((VarAst) t.getLeftArgument()).name()); - assertEquals("", ((IriAst) t.getRightArgument()).raw()); + assertEquals("s", varAst.name()); + assertEquals("2", literalAst.lexical()); } @Test @@ -515,7 +515,7 @@ void shouldParseLowerOrEqualFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(?s <= ) + FILTER(?s <= 3) } """); @@ -533,11 +533,11 @@ void shouldParseLowerOrEqualFilter() { LowerOrEqualThanAst t = (LowerOrEqualThanAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getLeftArgument()); - assertInstanceOf(IriAst.class, t.getRightArgument()); + VarAst varAst = assertInstanceOf(VarAst.class, t.getLeftArgument()); + LiteralAst literalAst = assertInstanceOf(LiteralAst.class, t.getRightArgument()); - assertEquals("s", ((VarAst) t.getLeftArgument()).name()); - assertEquals("", ((IriAst) t.getRightArgument()).raw()); + assertEquals("s", varAst.name()); + assertEquals("3", literalAst.lexical()); } @Test @@ -547,7 +547,7 @@ void shouldParseGreaterFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(?s > ) + FILTER(?s > 4) } """); @@ -565,11 +565,11 @@ void shouldParseGreaterFilter() { GreaterThanAst t = (GreaterThanAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getLeftArgument()); - assertInstanceOf(IriAst.class, t.getRightArgument()); + VarAst varAst = assertInstanceOf(VarAst.class, t.getLeftArgument()); + LiteralAst literalAst = assertInstanceOf(LiteralAst.class, t.getRightArgument()); - assertEquals("s", ((VarAst) t.getLeftArgument()).name()); - assertEquals("", ((IriAst) t.getRightArgument()).raw()); + assertEquals("s", varAst.name()); + assertEquals("4", literalAst.lexical()); } @Test @@ -579,7 +579,7 @@ void shouldParseGreaterOrEqualFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(?s >= ) + FILTER(?s >= 5) } """); @@ -597,11 +597,11 @@ void shouldParseGreaterOrEqualFilter() { GreaterOrEqualThanAst t = (GreaterOrEqualThanAst) filterAst.operator(); - assertInstanceOf(VarAst.class, t.getLeftArgument()); - assertInstanceOf(IriAst.class, t.getRightArgument()); + VarAst varAst = assertInstanceOf(VarAst.class, t.getLeftArgument()); + LiteralAst literalAst = assertInstanceOf(LiteralAst.class, t.getRightArgument()); - assertEquals("s", ((VarAst) t.getLeftArgument()).name()); - assertEquals("", ((IriAst) t.getRightArgument()).raw()); + assertEquals("s", varAst.name()); + assertEquals("5", literalAst.lexical()); } @Test @@ -948,8 +948,8 @@ void shouldParseAddsUnaryMinusEqualsFilter() { assertEquals("s", ((VarAst) addAst.getLeftArgument()).name()); assertInstanceOf(UnaryMinusAst.class, addAst.getRightArgument()); UnaryMinusAst rightUnaryMinusAst = (UnaryMinusAst) addAst.getRightArgument(); - assertInstanceOf(LiteralAst.class, rightUnaryMinusAst.getArgument()); - assertEquals("2", ((LiteralAst) rightUnaryMinusAst.getArgument()).lexical()); + assertInstanceOf(LiteralAst.class, rightUnaryMinusAst.argument()); + assertEquals("2", ((LiteralAst) rightUnaryMinusAst.argument()).lexical()); } @Test @@ -1042,7 +1042,7 @@ void shouldParseUnaryPlusFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(+ ?s) + FILTER(+ ?s > 0) } """); @@ -1053,16 +1053,13 @@ void shouldParseUnaryPlusFilter() { assertEquals(2, where.patterns().size(), "WHERE should contain 2 pattern (BGP + FILTER)"); PatternAst p2 = where.patterns().getLast(); - assertInstanceOf(FilterAst.class, p2, "Last pattern should be a filter"); - - FilterAst filterAst = (FilterAst) p2; - assertInstanceOf(UnaryPlusAst.class, filterAst.operator(), "Filter content should be a unary plus operator"); - - UnaryPlusAst t = (UnaryPlusAst) filterAst.operator(); + FilterAst filterAst = assertInstanceOf(FilterAst.class, p2, "Last pattern should be a filter"); + GreaterThanAst greaterThanAst = assertInstanceOf(GreaterThanAst.class, filterAst.operator(), "Filter content should be a greater than comparison"); + UnaryPlusAst t = assertInstanceOf(UnaryPlusAst.class, greaterThanAst.getLeftArgument(), "Comparison content should be a unary plus operator"); - assertInstanceOf(VarAst.class, t.getArgument()); + assertInstanceOf(VarAst.class, t.argument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -1072,7 +1069,7 @@ void shouldParseUnaryMinusFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(- ?s) + FILTER(- ?s > 0) } """); @@ -1083,15 +1080,12 @@ void shouldParseUnaryMinusFilter() { assertEquals(2, where.patterns().size(), "WHERE should contain 2 pattern (BGP + FILTER)"); PatternAst p2 = where.patterns().getLast(); - assertInstanceOf(FilterAst.class, p2, "Last pattern should be a filter"); - - FilterAst filterAst = (FilterAst) p2; - assertInstanceOf(UnaryMinusAst.class, filterAst.operator(), "Filter content should be a unary minus operator"); - - UnaryMinusAst t = (UnaryMinusAst) filterAst.operator(); + FilterAst filterAst = assertInstanceOf(FilterAst.class, p2, "Last pattern should be a filter"); + GreaterThanAst greaterThanAst = assertInstanceOf(GreaterThanAst.class, filterAst.operator(), "Filter content should be a greater than comparison"); + UnaryMinusAst t = assertInstanceOf(UnaryMinusAst.class, greaterThanAst.getLeftArgument(), "comparison content should be a unary minus operator"); - assertInstanceOf(VarAst.class, t.getArgument()); - assertEquals("s", ((VarAst) t.getArgument()).name()); + assertInstanceOf(VarAst.class, t.argument()); + assertEquals("s", ((VarAst) t.argument()).name()); } @Test @@ -1314,9 +1308,9 @@ void shouldParseNotOverExistsFilter() { assertInstanceOf(BooleanNotAst.class, filterAst.operator()); BooleanNotAst booleanNotAst = (BooleanNotAst) filterAst.operator(); - assertInstanceOf(ExistsAst.class, booleanNotAst.getArgument()); + assertInstanceOf(ExistsAst.class, booleanNotAst.argument()); - ExistsAst existsAst = (ExistsAst) booleanNotAst.getArgument(); + ExistsAst existsAst = (ExistsAst) booleanNotAst.argument(); assertNotNull(existsAst.pattern()); assertFalse(existsAst.pattern().patterns().isEmpty()); } @@ -1337,9 +1331,9 @@ void shouldParseNotOverNotExistsFilter() { assertInstanceOf(BooleanNotAst.class, filterAst.operator()); BooleanNotAst booleanNotAst = (BooleanNotAst) filterAst.operator(); - assertInstanceOf(NotExistsAst.class, booleanNotAst.getArgument()); + assertInstanceOf(NotExistsAst.class, booleanNotAst.argument()); - NotExistsAst notExistsAst = (NotExistsAst) booleanNotAst.getArgument(); + NotExistsAst notExistsAst = (NotExistsAst) booleanNotAst.argument(); assertNotNull(notExistsAst.pattern()); assertFalse(notExistsAst.pattern().patterns().isEmpty()); } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserHashFunctionsTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserHashFunctionsTest.java index 4249436eb..61654b1e0 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserHashFunctionsTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserHashFunctionsTest.java @@ -35,7 +35,7 @@ void shouldParseMd5InBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); Md5Ast md5 = assertInstanceOf(Md5Ast.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, md5.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, md5.argument()).name()); assertEquals("hash", bind.variable().name()); } @@ -54,7 +54,7 @@ void shouldParseSha1InBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); Sha1Ast sha1 = assertInstanceOf(Sha1Ast.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, sha1.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, sha1.argument()).name()); assertEquals("hash", bind.variable().name()); } @@ -73,7 +73,7 @@ void shouldParseSha256InBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); Sha256Ast sha256 = assertInstanceOf(Sha256Ast.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, sha256.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, sha256.argument()).name()); assertEquals("hash", bind.variable().name()); } @@ -92,7 +92,7 @@ void shouldParseSha384InBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); Sha384Ast sha384 = assertInstanceOf(Sha384Ast.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, sha384.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, sha384.argument()).name()); assertEquals("hash", bind.variable().name()); } @@ -111,7 +111,7 @@ void shouldParseSha512InBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); Sha512Ast sha512 = assertInstanceOf(Sha512Ast.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, sha512.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, sha512.argument()).name()); assertEquals("hash", bind.variable().name()); } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserIriTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserIriTest.java index 5944a9724..bee4a25fc 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserIriTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserIriTest.java @@ -31,7 +31,7 @@ void shouldParseIriInBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); IriFunctionAst iri = assertInstanceOf(IriFunctionAst.class, bind.expression()); - assertEquals("lex", assertInstanceOf(VarAst.class, iri.getArgument()).name()); + assertEquals("lex", assertInstanceOf(VarAst.class, iri.argument()).name()); assertEquals("iri", bind.variable().name()); } @@ -50,7 +50,7 @@ void shouldParseUriAliasInBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); IriFunctionAst iri = assertInstanceOf(IriFunctionAst.class, bind.expression()); - assertEquals("lex", assertInstanceOf(VarAst.class, iri.getArgument()).name()); + assertEquals("lex", assertInstanceOf(VarAst.class, iri.argument()).name()); assertEquals("iri", bind.variable().name()); } @@ -70,7 +70,7 @@ void shouldParseIriInFilterComparison() { FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); EqualsAst equals = assertInstanceOf(EqualsAst.class, filter.operator()); IriFunctionAst iri = assertInstanceOf(IriFunctionAst.class, equals.getLeftArgument()); - assertEquals("lex", assertInstanceOf(VarAst.class, iri.getArgument()).name()); + assertEquals("lex", assertInstanceOf(VarAst.class, iri.argument()).name()); assertEquals("", assertInstanceOf(IriAst.class, equals.getRightArgument()).raw()); } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserLcaseTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserLcaseTest.java index 2c7c522f4..155eda929 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserLcaseTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserLcaseTest.java @@ -31,7 +31,7 @@ void shouldParseLcaseInBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); LcaseAst lcase = assertInstanceOf(LcaseAst.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, lcase.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, lcase.argument()).name()); assertEquals("lower", bind.variable().name()); } @@ -50,7 +50,7 @@ void shouldParseLcaseWithLiteralArgument() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); LcaseAst lcase = assertInstanceOf(LcaseAst.class, bind.expression()); - LiteralAst literal = assertInstanceOf(LiteralAst.class, lcase.getArgument()); + LiteralAst literal = assertInstanceOf(LiteralAst.class, lcase.argument()); assertEquals("\"CORESE\"", literal.lexical()); assertEquals("lower", bind.variable().name()); } @@ -71,7 +71,7 @@ void shouldParseLcaseInFilterComparison() { FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); EqualsAst equals = assertInstanceOf(EqualsAst.class, filter.operator()); LcaseAst lcase = assertInstanceOf(LcaseAst.class, equals.getLeftArgument()); - assertEquals("label", assertInstanceOf(VarAst.class, lcase.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, lcase.argument()).name()); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserNumericFunctionsTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserNumericFunctionsTest.java index 02715cd93..efbca7e8e 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserNumericFunctionsTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserNumericFunctionsTest.java @@ -2,11 +2,7 @@ import fr.inria.corese.core.next.query.api.exception.QueryValidationException; import fr.inria.corese.core.next.query.impl.sparql.ast.*; -import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.AbsAst; -import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.CeilAst; -import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.FloorAst; -import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.RandAst; -import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.RoundAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -34,7 +30,7 @@ void shouldParseAbsInBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); AbsAst abs = assertInstanceOf(AbsAst.class, bind.expression()); - assertEquals("x", assertInstanceOf(VarAst.class, abs.getArgument()).name()); + assertEquals("x", assertInstanceOf(VarAst.class, abs.argument()).name()); assertEquals("abs", bind.variable().name()); } @@ -46,14 +42,15 @@ void shouldParseRoundInFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(ROUND(?x)) + FILTER(ROUND(?x) > 0) } """); assertNotNull(ast); FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); - RoundAst round = assertInstanceOf(RoundAst.class, filter.operator()); - assertEquals("x", assertInstanceOf(VarAst.class, round.getArgument()).name()); + GreaterThanAst greaterThanAst = assertInstanceOf(GreaterThanAst.class, filter.operator()); + RoundAst round = assertInstanceOf(RoundAst.class, greaterThanAst.getLeftArgument()); + assertEquals("x", assertInstanceOf(VarAst.class, round.argument()).name()); } @Test @@ -64,14 +61,15 @@ void shouldParseCeilInFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(CEIL(?x)) + FILTER(CEIL(?x) > 0) } """); assertNotNull(ast); FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); - CeilAst ceil = assertInstanceOf(CeilAst.class, filter.operator()); - assertEquals("x", assertInstanceOf(VarAst.class, ceil.getArgument()).name()); + GreaterThanAst greaterThanAst = assertInstanceOf(GreaterThanAst.class, filter.operator()); + CeilAst ceil = assertInstanceOf(CeilAst.class, greaterThanAst.getLeftArgument()); + assertEquals("x", assertInstanceOf(VarAst.class, ceil.argument()).name()); } @Test @@ -82,14 +80,15 @@ void shouldParseFloorInFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(FLOOR(?x)) + FILTER(FLOOR(?x) > 0) } """); assertNotNull(ast); FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); - FloorAst floor = assertInstanceOf(FloorAst.class, filter.operator()); - assertEquals("x", assertInstanceOf(VarAst.class, floor.getArgument()).name()); + GreaterThanAst greaterThanAst = assertInstanceOf(GreaterThanAst.class, filter.operator()); + FloorAst floor = assertInstanceOf(FloorAst.class, greaterThanAst.getLeftArgument()); + assertEquals("x", assertInstanceOf(VarAst.class, floor.argument()).name()); } @Test @@ -118,13 +117,14 @@ void shouldParseRandInFilter() { SparqlQueryAst ast = (SparqlQueryAst) parser.parse(""" SELECT * WHERE { ?s ?p ?o . - FILTER(RAND()) + FILTER(RAND() > 0) } """); assertNotNull(ast); FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); - assertInstanceOf(RandAst.class, filter.operator()); + GreaterThanAst greaterThanAst = assertInstanceOf(GreaterThanAst.class, filter.operator()); + assertInstanceOf(RandAst.class, greaterThanAst.getLeftArgument()); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserStrUuidTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserStrUuidTest.java index 0e1ed610d..f5121e984 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserStrUuidTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserStrUuidTest.java @@ -50,7 +50,7 @@ void shouldParseStrUuidInFilter() { EqualsAst equals = assertInstanceOf(EqualsAst.class, filter.operator()); assertInstanceOf(StrUuidAst.class, equals.getLeftArgument()); StrAst str = assertInstanceOf(StrAst.class, equals.getRightArgument()); - assertEquals("s", assertInstanceOf(VarAst.class, str.getArgument()).name()); + assertEquals("s", assertInstanceOf(VarAst.class, str.argument()).name()); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserUcaseTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserUcaseTest.java index bae52dc24..e14753908 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserUcaseTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserUcaseTest.java @@ -31,7 +31,7 @@ void shouldParseUcaseInBind() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); UcaseAst ucase = assertInstanceOf(UcaseAst.class, bind.expression()); - assertEquals("label", assertInstanceOf(VarAst.class, ucase.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, ucase.argument()).name()); assertEquals("upper", bind.variable().name()); } @@ -50,7 +50,7 @@ void shouldParseUcaseWithLiteralArgument() { assertNotNull(ast); BindAst bind = assertInstanceOf(BindAst.class, ast.whereClause().patterns().getLast()); UcaseAst ucase = assertInstanceOf(UcaseAst.class, bind.expression()); - LiteralAst literal = assertInstanceOf(LiteralAst.class, ucase.getArgument()); + LiteralAst literal = assertInstanceOf(LiteralAst.class, ucase.argument()); assertEquals("\"corese\"", literal.lexical()); assertEquals("upper", bind.variable().name()); } @@ -71,7 +71,7 @@ void shouldParseUcaseInFilterComparison() { FilterAst filter = assertInstanceOf(FilterAst.class, ast.whereClause().patterns().getLast()); EqualsAst equals = assertInstanceOf(EqualsAst.class, filter.operator()); UcaseAst ucase = assertInstanceOf(UcaseAst.class, equals.getLeftArgument()); - assertEquals("label", assertInstanceOf(VarAst.class, ucase.getArgument()).name()); + assertEquals("label", assertInstanceOf(VarAst.class, ucase.argument()).name()); } @Test diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserValidationTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserValidationTest.java index 956e4826c..156f90994 100644 --- a/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserValidationTest.java +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/SparqlParserValidationTest.java @@ -10,8 +10,7 @@ import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; class SparqlParserValidationTest extends AbstractSparqlParserFeatureTest { @@ -43,14 +42,14 @@ void shouldRejectConstructOrderByVariableNotVisibleInWhere() { SparqlParser parser = newParserDefault(); QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" - CONSTRUCT { - ?s ?p ?o - } - WHERE { - ?s ?p ?o - } - ORDER BY ?z - """)); + CONSTRUCT { + ?s ?p ?o + } + WHERE { + ?s ?p ?o + } + ORDER BY ?z + """)); assertEquals(ORDER_BY_SCOPE_MESSAGE, exception.getMessage()); } @@ -65,12 +64,12 @@ void shouldRejectDescribeOrderByVariableNotVisibleInWhere() { SparqlParser parser = newParserDefault(); QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" - DESCRIBE ?s - WHERE { - ?s ?p ?o - } - ORDER BY ?z - """)); + DESCRIBE ?s + WHERE { + ?s ?p ?o + } + ORDER BY ?z + """)); assertEquals(ORDER_BY_SCOPE_MESSAGE, exception.getMessage()); } @@ -85,11 +84,11 @@ void shouldRejectBindVariableAlreadyVisibleFromTriple() { SparqlParser parser = newParserDefault(); QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" - SELECT * WHERE { - ?x ?p ?o . - BIND(?o AS ?x) - } - """)); + SELECT * WHERE { + ?x ?p ?o . + BIND(?o AS ?x) + } + """)); assertEquals(BIND_SCOPE_MESSAGE, exception.getMessage()); } @@ -100,91 +99,525 @@ void shouldRejectBindVariableAlreadyVisibleFromPreviousBind() { SparqlParser parser = newParserDefault(); QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" - SELECT * WHERE { - ?s ?p ?o . - BIND(?s AS ?x) - BIND(?p AS ?x) - } - """)); + SELECT * WHERE { + ?s ?p ?o . + BIND(?s AS ?x) + BIND(?p AS ?x) + } + """)); assertEquals(BIND_SCOPE_MESSAGE, exception.getMessage()); } } + @Nested + class FilterValidationTest { + + @Test + @DisplayName("Should reject FILTER with numeric operator") + void shouldRejectFilterWithNumericOperator() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(RAND()) + } + """)); + + assertEquals("RAND used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject FILTER with IRI operator") + void shouldRejectFilterWithIRIOperator() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(DATATYPE("test"^^)) + } + """)); + + assertEquals("DATATYPE used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject FILTER with datetime operator") + void shouldRejectFilterWithDatetime() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(NOW()) + } + """)); + + assertEquals("NOW used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject FILTER with datetime duration operator") + void shouldRejectFilterWithDuration() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(DAY(NOW())) + } + """)); + + assertEquals("DAY used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should let pass FILTER with simple literal operator") + void shouldAcceptFilterWithStringOperator() { + SparqlParser parser = newParserDefault(); + + assertDoesNotThrow(() -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(STR("test"^^)) + } + """)); + } + + @Test + @DisplayName("Should let pass FILTER with variable") + void shouldAcceptFilterWithVariable() { + SparqlParser parser = newParserDefault(); + + assertDoesNotThrow(() -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(?o) + } + """)); + } + + @Test + @DisplayName("Should let pass FILTER with boolean") + void shouldAcceptFilterWithBoolean() { + SparqlParser parser = newParserDefault(); + + assertDoesNotThrow(() -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(true) + } + """)); + } + + @Test + @DisplayName("Should let pass FILTER containing a IF that returns boolean or any acceptable AST type.") + void shouldAcceptFilterContainingIfWithCorrectType() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(IF(?s, true, ?o)) + } + """); + }); + } + + @Test + @DisplayName("Should reject FILTER containing a IF that does not returns boolean or any acceptable AST type.") + void shouldRejectFilterContainingIfWithIncorrectType() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(IF(?s, 4, )) + } + """)); + + assertEquals("IF used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject FILTER containing a IF that does not returns only boolean or any acceptable AST type.") + void shouldRejectFilterContainingIfWithIncorrectTypeMix() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(IF(?s, true, )) + } + """)); + + assertEquals("IF used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject FILTER with numeric operator in a nested BGP") + void shouldRejectFilterWithNumericOperatorInNestedBGP() { + SparqlParser parser = newParserDefault(); + + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> parser.parse(""" + SELECT * WHERE { + { + ?x ?p ?o . + FILTER(RAND()) + } UNION { + ?s ?p ?o . + } + } + """)); + + assertEquals("RAND used in FILTER should be resolvable to a boolean", exception.getMessage()); + } + } + + @Nested + public class OperandTypeTest { + + @Test + @DisplayName("Should accept + operator with numerics") + void shouldAcceptPlusWithNumerics() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(RAND() + 1 = ?o) + } + """); + }); + } + + @Test + @DisplayName("Should accept - operator with numerics") + void shouldAcceptMinusWithNumerics() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(STRLEN("test") - 1 = ?o) + } + """); + }); + } + + @Test + @DisplayName("Should accept * operator with numerics") + void shouldAcceptMultiplyWithNumerics() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(STRLEN("test") * RAND() = ?o) + } + """); + }); + } + + @Test + @DisplayName("Should accept / operator with numerics") + void shouldAcceptDivideWithNumerics() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(DAY(NOW()) / 2 = ?o) + } + """); + }); + } + + @Test + @DisplayName("Should reject + operator with non numerics") + void shouldRefusePlusWithNonNumerics() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(RAND() + "one" = ?o) + } + """); + }); + assertEquals("\"one\" used in + should be resolvable to a numeric", exception.getMessage()); + } + + @Test + @DisplayName("Should reject - operator with non numerics") + void shouldRejectMinusWithNonNumerics() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER((3 - STRENDS("test", "")) = ?o) + } + """); + }); + assertEquals("STRENDS used in - should be resolvable to a numeric", exception.getMessage()); + } + + @Test + @DisplayName("Should reject * operator with non numerics") + void shouldRejectDivideWithNonNumerics() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER( / 2 = ?o) + } + """); + }); + assertEquals(" used in / should be resolvable to a numeric", exception.getMessage()); + } + + @Test + @DisplayName("Should reject / operator with non numerics") + void shouldRejectMultiplyWithNonNumerics() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(STRLEN("test") * NOW() = ?o) + } + """); + }); + assertEquals("NOW used in * should be resolvable to a numeric", exception.getMessage()); + } + + @Test + @DisplayName("Should accept || operator with booleans") + void shouldAcceptOrWithBoolean() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(IsIri(?s) || false) + } + """); + }); + } + + @Test + @DisplayName("Should accept && operator with booleans") + void shouldAcceptAndWithBoolean() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(NOT EXISTS { ?s ?p false } && STRSTARTS("test", "t")) + } + """); + }); + } + + @Test + @DisplayName("Should reject || operator with non booleans") + void shouldRejectOrWithNonBoolean() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(IsIri(?s) || "potato") + } + """); + }); + assertEquals("\"potato\" used in || should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject && operator with non booleans") + void shouldRejectAndWithNonBoolean() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER( && langMatches("potato", "fr")) + } + """); + }); + assertEquals(" used in && should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should accept ! operator with booleans") + void shouldAcceptNotWithBoolean() { + SparqlParser parser = newParserDefault(); + assertDoesNotThrow(() -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(! NOT EXISTS { ?s ?p false } && STRSTARTS("test", "t")) + } + """); + }); + } + + @Test + @DisplayName("Should reject ! operator with non booleans") + void shouldRejectNotWithNonBoolean() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(! ) + } + """); + }); + assertEquals(" used in ! should be resolvable to a boolean", exception.getMessage()); + } + + @Test + @DisplayName("Should reject < operator with IRIs") + void shouldRejectLTWithIRIs() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(2 < ) + } + """); + }); + assertEquals(" used in < should be resolvable to a not an IRI", exception.getMessage()); + } + + @Test + @DisplayName("Should reject <= operator with IRIs") + void shouldRejectLTEWithIRIs() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(STRLEN("test") <= ) + } + """); + }); + assertEquals(" used in <= should be resolvable to a not an IRI", exception.getMessage()); + } + + @Test + @DisplayName("Should reject > operator with IRIs") + void shouldRejectGTWithIRIs() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER("2"^^ > ) + } + """); + }); + assertEquals(" used in > should be resolvable to a not an IRI", exception.getMessage()); + } + + @Test + @DisplayName("Should reject >= operator with IRIs") + void shouldRejectGTEWithIRIs() { + SparqlParser parser = newParserDefault(); + QueryValidationException exception = assertThrows(QueryValidationException.class, () -> { + parser.parse(""" + SELECT * WHERE { + ?x ?p ?o . + FILTER(datatype("2"^^) >= 4) + } + """); + }); + assertEquals("DATATYPE used in >= should be resolvable to a not an IRI", exception.getMessage()); + } + + } + private static Stream invalidSelectQueries() { return Stream.of( Arguments.of( "Should reject SELECT * with ORDER BY variable not visible in WHERE", """ - SELECT * WHERE { - ?s ?p ?o - } - ORDER BY ?z - """, + SELECT * WHERE { + ?s ?p ?o + } + ORDER BY ?z + """, ORDER_BY_SCOPE_MESSAGE), Arguments.of( "Should reject projection variable only referenced in FILTER", """ - SELECT ?x WHERE { - ?s ?p ?o . - FILTER(BOUND(?x)) - } - """, + SELECT ?x WHERE { + ?s ?p ?o . + FILTER(BOUND(?x)) + } + """, SELECT_PROJECTION_SCOPE_MESSAGE), Arguments.of( "Should reject projection variable not visible through UNION", """ - SELECT ?cityLabel - WHERE { - { ?country wdt:P36 ?city. } - UNION - { ?city wdt:P17 ?country. } - } - """, + SELECT ?cityLabel + WHERE { + { ?country wdt:P36 ?city. } + UNION + { ?city wdt:P17 ?country. } + } + """, CITY_LABEL_SCOPE_MESSAGE), Arguments.of( "Should reject ORDER BY variable not visible in WHERE", """ - SELECT ?s WHERE { - ?s ?p ?o - } - ORDER BY ?z - """, + SELECT ?s WHERE { + ?s ?p ?o + } + ORDER BY ?z + """, ORDER_BY_SCOPE_MESSAGE), Arguments.of( "Should reject multiple ORDER BY clauses when one variable is not visible in WHERE", """ - SELECT ?s WHERE { - ?s ?p ?o - } - ORDER BY ?s ?z - """, + SELECT ?s WHERE { + ?s ?p ?o + } + ORDER BY ?s ?z + """, ORDER_BY_SCOPE_MESSAGE), Arguments.of( "Should reject ORDER BY expression using a variable not visible in WHERE", """ - SELECT ?s WHERE { - ?s ?p ?o - } - ORDER BY STR(?z) - """, + SELECT ?s WHERE { + ?s ?p ?o + } + ORDER BY STR(?z) + """, ORDER_BY_SCOPE_MESSAGE), Arguments.of( "Should reject ORDER BY IF expression using a variable not visible in WHERE", """ - SELECT ?s WHERE { - ?s ?p ?o - } - ORDER BY IF(BOUND(?o), ?o, ?z) - """, + SELECT ?s WHERE { + ?s ?p ?o + } + ORDER BY IF(BOUND(?o), ?o, ?z) + """, ORDER_BY_SCOPE_MESSAGE), Arguments.of( "Should reject SELECT projection variables not visible in WHERE", """ - SELECT ?x WHERE { - ?s ?p ?o - } - """, + SELECT ?x WHERE { + ?s ?p ?o + } + """, SELECT_PROJECTION_SCOPE_MESSAGE)); } } diff --git a/src/test/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/SemanticValidationUtilsTest.java b/src/test/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/SemanticValidationUtilsTest.java new file mode 100644 index 000000000..683f927af --- /dev/null +++ b/src/test/java/fr/inria/corese/core/next/query/impl/parser/semantic/support/SemanticValidationUtilsTest.java @@ -0,0 +1,58 @@ +package fr.inria.corese.core.next.query.impl.parser.semantic.support; + +import fr.inria.corese.core.next.data.impl.common.vocabulary.XSD; +import fr.inria.corese.core.next.query.impl.sparql.ast.IriAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.LiteralAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst; +import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.*; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static fr.inria.corese.core.next.query.impl.parser.semantic.support.SemanticValidationUtils.*; +import static org.junit.jupiter.api.Assertions.*; + +class SemanticValidationUtilsTest { + + @Test + void checkTermIsPotentialBooleanTest() { + assertTrue(checkTermIsPotentialBoolean(new LiteralAst("true", null, null))); + assertTrue(checkTermIsPotentialBoolean(new LiteralAst("potato", null, XSD.xsdBoolean.getIRI().stringValue()))); + assertTrue(checkTermIsPotentialBoolean(new AndAst(List.of(new LiteralAst("true", null, null), new LiteralAst("true", null, null))))); + assertTrue(checkTermIsPotentialBoolean(new VarAst("test"))); + assertFalse(checkTermIsPotentialBoolean(new IriAst(""))); + assertFalse(checkTermIsPotentialBoolean(new NowAst())); + } + + @Test + void checkTermIsPotentialNumericTest() { + assertTrue(checkTermIsPotentialNumeric(new LiteralAst("1", null, null))); + assertTrue(checkTermIsPotentialNumeric(new LiteralAst("abc", null, XSD.xsdDouble.getIRI().stringValue()))); + assertTrue(checkTermIsPotentialNumeric(new VarAst("test"))); + assertFalse(checkTermIsPotentialNumeric(new IriAst(""))); + assertFalse(checkTermIsPotentialNumeric(new NowAst())); + assertTrue(checkTermIsPotentialNumeric(new AddAst(List.of(new LiteralAst("1", null, null), new LiteralAst("2", null, null))))); + } + + @Test + void checkTermIsUnknownTypeTest() { + assertTrue(checkTermIsUnknownType(new VarAst("test"))); + assertFalse(checkTermIsUnknownType(new LiteralAst("true", null, null))); + assertFalse(checkTermIsUnknownType(new NowAst())); + } + + @Test + void checkStringIsNumericTest() { + assertTrue(checkStringIsNumeric("1")); + assertFalse(checkStringIsNumeric("Potato")); + } + + @Test + void checkTermIsPotentialIriTest() { + assertTrue(checkTermIsPotentialIri(new IriAst(""))); + assertTrue(checkTermIsPotentialIri(new DatatypeAst(List.of(new LiteralAst("1", null, null))))); + assertFalse(checkTermIsPotentialIri(new VarAst("test"))); + assertFalse(checkTermIsPotentialIri(new LiteralAst("1", null, null))); + assertFalse(checkTermIsPotentialIri(new NowAst())); + } +} \ No newline at end of file