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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public DatatypeValue getValue() {
SparqlTermResolver resolver = whereCompiler == null
? new SparqlTermResolver(null)
: whereCompiler.termResolver();
return CoreseAstQueryBuilder.toNode(source, resolver).getDatatypeValue();
return resolver.toNode(source).getDatatypeValue();
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

import fr.inria.corese.core.next.query.api.exception.UnsupportedQueryFeatureException;
import fr.inria.corese.core.next.query.impl.sparql.ast.*;
import fr.inria.corese.core.next.query.impl.sparql.ast.path.PathAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.path.PredicatePathAst;
import fr.inria.corese.core.next.query.impl.engine.model.ExpType.Type;
import fr.inria.corese.core.next.query.impl.engine.model.Filter;
import fr.inria.corese.core.next.query.impl.engine.model.Node;
Expand Down Expand Up @@ -172,41 +170,6 @@ public Filter toNextFilter(ConstraintAst filterExpression) {
return new AstBackedExpr(filterExpression, whereCompiler).getFilter();
}

/**
* Converts a query term used as subject, predicate, object, or variable reference
* into a runtime {@link Node}.
*
* <p>This helper is package-visible because both the query builder and the
* {@link WhereCompiler} need a single shared term-to-node conversion rule.</p>
*/
static Node toNode(TermAst term) {
return toNode(term, new SparqlTermResolver(null));
}

static Node toNode(TermAst term, SparqlTermResolver resolver) {
return switch (term) {
case VarAst(String name) -> NodeImpl.forVariable(name);
case IriAst(String raw) when raw.startsWith("_:") -> NodeImpl.forBlank(raw.substring(2));
case IriAst(String raw) -> NodeImpl.forIRI(resolver.resolveIri(raw));
case LiteralAst(String lexical, String lang, String datatype) -> NodeImpl.forLiteral(
resolver.unquoteLexical(lexical),
resolver.normalizeDatatypeIri(datatype),
lang);
default -> throw new IllegalArgumentException(
"A query term must be a variable, IRI or literal, got: "
+ term.getClass().getSimpleName());
};
}

static TermAst simplePredicate(PathAst path) {
if (path instanceof PredicatePathAst(TermAst predicate)) {
return predicate;
}
throw new UnsupportedQueryFeatureException(
"Property path bridge compilation is not supported yet by the next pipeline for: "
+ path.getClass().getSimpleName());
}

/**
* Rejects unsupported clauses for {@code ASK} queries.
*
Expand Down Expand Up @@ -318,7 +281,7 @@ private void applyDataset(Query query, DatasetClauseAst datasetClause, WhereComp
private List<Node> toNodeList(Iterable<IriAst> iris, WhereCompiler compiler) {
List<Node> nodes = new ArrayList<>();
for (IriAst iri : iris) {
nodes.add(toNode(iri, compiler.termResolver()));
nodes.add(compiler.termResolver().toNode(iri));
}
return nodes;
}
Expand Down Expand Up @@ -371,7 +334,7 @@ private List<Node> describeNodes(
}
nodes.add(node);
} else {
nodes.add(toNode(term, compiler.termResolver()));
nodes.add(compiler.termResolver().toNode(term));
}
}
return nodes;
Expand Down Expand Up @@ -540,7 +503,8 @@ private Exp compileConstructTemplate(
Exp bgp = Exp.create(Type.BGP);
for (TriplePatternAst triple : template.triplePatternAsts()) {
Node subject = constructNode(query, triple.subject(), compiler);
Node predicate = constructNode(query, simplePredicate(triple.predicate()), compiler);
Node predicate = constructNode(
query, WhereCompiler.simplePredicate(triple.predicate()), compiler);
Node object = constructNode(query, triple.object(), compiler);
bgp.add(new AstBackedEdge(subject, predicate, object));
}
Expand All @@ -556,8 +520,8 @@ private Exp compileConstructTemplate(
private Node constructNode(Query query, TermAst term, WhereCompiler compiler) {
if (term instanceof VarAst(String name)) {
Node bound = visibleBodyNode(query, name);
return bound != null ? bound : toNode(term, compiler.termResolver());
return bound != null ? bound : compiler.termResolver().toNode(term);
}
return toNode(term, compiler.termResolver());
return compiler.termResolver().toNode(term);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ DatatypeValue variable(String name) {
}

DatatypeValue constant(TermAst expression) {
return CoreseAstQueryBuilder.toNode(expression, termResolver()).getDatatypeValue();
return termResolver().toNode(expression).getDatatypeValue();
}

DatatypeValue required(TermAst expression) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package fr.inria.corese.core.next.query.impl.sparql.bridge;


import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst;
import fr.inria.corese.core.next.query.impl.engine.model.Expr;
import fr.inria.corese.core.next.query.impl.engine.model.Filter;
Expand All @@ -10,9 +9,7 @@
import java.util.List;
import java.util.Optional;

/**
* {@link Filter} view exposing native AST metadata through the Corese-next {@link Expr} API.
*/
/** Filter view exposing native AST metadata through the Corese-next expression API. */
public final class NextFilterFromAst implements Filter {

private final AstBackedExpr owner;
Expand Down Expand Up @@ -71,4 +68,4 @@ public boolean isRecExist() {
public Optional<TermAst> coreseNextSource() {
return owner.sourceAst();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
import fr.inria.corese.core.next.data.impl.namespace.PrefixHandler;
import fr.inria.corese.core.next.data.spi.io.IOConstants;
import fr.inria.corese.core.next.data.spi.term.IRIUtils;
import fr.inria.corese.core.next.query.impl.engine.model.Node;
import fr.inria.corese.core.next.query.impl.engine.model.NodeImpl;
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.PrefixDeclarationAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryPrologueAst;

import java.util.Objects;
import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst;

/** Resolves SPARQL terms against one immutable query-prologue snapshot. */
public final class SparqlTermResolver {
Expand Down Expand Up @@ -45,6 +49,20 @@ public String resolveIri(String raw) {
return resolvePrefixedIri(raw);
}

public Node toNode(TermAst term) {
return switch (term) {
case VarAst(String name) -> NodeImpl.forVariable(name);
case IriAst(String raw) when raw.startsWith(IOConstants.BLANK_NODE_PREFIX) ->
NodeImpl.forBlank(raw.substring(IOConstants.BLANK_NODE_PREFIX.length()));
case IriAst(String raw) -> NodeImpl.forIRI(resolveIri(raw));
case LiteralAst(String lexical, String lang, String datatype) -> NodeImpl.forLiteral(
unquoteLexical(lexical), normalizeDatatypeIri(datatype), lang);
default -> throw new IllegalArgumentException(
"A query term must be a variable, IRI or literal, got: "
+ term.getClass().getSimpleName());
};
}

public String normalizeDatatypeIri(String datatype) {
if (datatype == null || datatype.isEmpty()) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
import fr.inria.corese.core.next.query.impl.sparql.ast.PatternAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryPrologueAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.ServiceAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.TermAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.TriplePatternAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.UnionAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.path.PathAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.path.PredicatePathAst;
import fr.inria.corese.core.next.query.impl.engine.model.Edge;
import fr.inria.corese.core.next.query.impl.engine.model.ExpType.Type;
import fr.inria.corese.core.next.query.impl.engine.model.Filter;
Expand Down Expand Up @@ -120,13 +123,22 @@ private Exp compileBgp(BgpAst bgp) {
}

private Edge toEdge(TriplePatternAst triple) {
Node subject = CoreseAstQueryBuilder.toNode(triple.subject(), termResolver);
Node predicate = CoreseAstQueryBuilder.toNode(
CoreseAstQueryBuilder.simplePredicate(triple.predicate()), termResolver);
Node object = CoreseAstQueryBuilder.toNode(triple.object(), termResolver);
Node subject = termResolver.toNode(triple.subject());
Node predicate = termResolver.toNode(
simplePredicate(triple.predicate()));
Node object = termResolver.toNode(triple.object());
return new AstBackedEdge(subject, predicate, object);
}

static TermAst simplePredicate(PathAst path) {
if (path instanceof PredicatePathAst(TermAst predicate)) {
return predicate;
}
throw new UnsupportedQueryFeatureException(
"Property path bridge compilation is not supported yet by the next pipeline for: "
+ path.getClass().getSimpleName());
}

private Exp compileFilter(FilterAst filter) {
Filter nextFilter = new AstBackedExpr(filter.operator(), this).getFilter();
return Exp.create(Type.FILTER, nextFilter);
Expand Down Expand Up @@ -165,7 +177,7 @@ private Exp compileMinus(MinusAst minus) {
*/
private Exp compileBind(BindAst bind) {
Filter filter = new AstBackedExpr(bind.expression(), this).getFilter();
Node variable = CoreseAstQueryBuilder.toNode(bind.variable(), termResolver);
Node variable = termResolver.toNode(bind.variable());
Exp exp = Exp.create(Type.BIND);
exp.setFilter(filter);
exp.setFunctional(filter.isFunctional());
Expand All @@ -177,7 +189,7 @@ private Exp compileBind(BindAst bind) {
* Compiles {@code SERVICE <endpoint> { ... }} into a KGRAM {@link Exp}.
*/
private Exp compileService(ServiceAst service) {
Node endpoint = CoreseAstQueryBuilder.toNode(service.endpoint(), termResolver);
Node endpoint = termResolver.toNode(service.endpoint());
Exp endpointNode = Exp.create(Type.NODE, endpoint);
Query body = Query.create(compile(service.pattern()));
body.setService(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package fr.inria.corese.core.next.query.impl.sparql.bridge;

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.PrefixDeclarationAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.QueryPrologueAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.VarAst;
import fr.inria.corese.core.next.query.impl.sparql.ast.constraint.BoundAst;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

@DisplayName("AstBackedExpr: AST wrapping, value resolution, and filter view")
class AstBackedExprTest {

@Test
void resolvesConstantUsingCompilerPrologue() {
QueryPrologueAst prologue = new QueryPrologueAst(
List.of(new PrefixDeclarationAst("ex:", new IriAst("http://example.org/"))),
null);
WhereCompiler compiler = new WhereCompiler().withPrologue(prologue);
AstBackedExpr expression = new AstBackedExpr(new IriAst("ex:name"), compiler);

assertEquals("http://example.org/name", expression.getValue().stringValue());
assertTrue(expression.isConstant());
assertFalse(expression.isVariable());
}

@Test
void resolvesLiteralValue() {
WhereCompiler compiler = new WhereCompiler();
AstBackedExpr stringExpr = new AstBackedExpr(new LiteralAst("\"hello\"", null, null), compiler);
assertEquals("hello", stringExpr.getValue().stringValue());

AstBackedExpr intExpr = new AstBackedExpr(new LiteralAst("42", null, "http://www.w3.org/2001/XMLSchema#integer"), compiler);
assertEquals("42", intExpr.getValue().stringValue());
}

@Test
void variableExpressionMetadata() {
WhereCompiler compiler = new WhereCompiler();
AstBackedExpr varExpr = new AstBackedExpr(new VarAst("x"), compiler);

assertEquals("x", varExpr.getLabel());
assertTrue(varExpr.isVariable());
assertFalse(varExpr.isConstant());
assertTrue(varExpr.getExpList().isEmpty());
assertNull(varExpr.getArg());
}

@Test
void boundExpressionAndFilterView() {
WhereCompiler compiler = new WhereCompiler();
BoundAst boundAst = new BoundAst(List.of(new VarAst("y")));
AstBackedExpr boundExpr = new AstBackedExpr(boundAst, compiler);

assertTrue(boundExpr.isBound());
assertNotNull(boundExpr.getFilter());
assertTrue(boundExpr.getFilter().isBound());
assertEquals(List.of("y"), boundExpr.getFilter().getVariables());
assertEquals(boundAst, boundExpr.getFilter().getFilterExpression());
}

@Test
void immutableExpressionsThrowOnModification() {
WhereCompiler compiler = new WhereCompiler();
AstBackedExpr expr = new AstBackedExpr(new VarAst("z"), compiler);

assertThrows(UnsupportedOperationException.class, () -> expr.setExp(0, expr));
assertThrows(UnsupportedOperationException.class, () -> expr.setArg(expr));
}
}
Loading