This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git

commit 304e2777dba475d7c37a7119f4d09257857287ca
Author: Andy Seaborne <[email protected]>
AuthorDate: Fri Dec 19 16:23:26 2025 +0000

    GH-3661: Allow 'true' and 'false' inside triple terms and reified triples
---
 .../org/apache/jena/riot/lang/LangTurtleBase.java  | 117 +++++++++++----------
 .../org/apache/jena/riot/lang/TestLangTurtle.java  |  17 ++-
 2 files changed, 74 insertions(+), 60 deletions(-)

diff --git 
a/jena-arq/src/main/java/org/apache/jena/riot/lang/LangTurtleBase.java 
b/jena-arq/src/main/java/org/apache/jena/riot/lang/LangTurtleBase.java
index d5e31bf425..86887bf474 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/lang/LangTurtleBase.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/lang/LangTurtleBase.java
@@ -342,9 +342,6 @@ public abstract class LangTurtleBase extends LangBase {
     }
 
     // -- rtSubject rules
-    // ??? profile.isValidTriple(s,p,o);
-    //profile.createTriple(s, p, o, token.getLine(), token.getColumn());
-
     private Node rtSubject(Token startToken) {
         if ( lookingAt(LT2) )
             return parseReifiedTriple();
@@ -365,8 +362,13 @@ public abstract class LangTurtleBase extends LangBase {
         Node o = possibleAnon() ;
         if ( o != null )
             return o;
+        o = possibleBooleanLiteral();
+        if (o != null )
+            return o;
+
         // Not compound triples (blankPredicateObjectList, collections).
         o = object();
+
         if ( ! (o.isURI() || o.isBlank() || o.isLiteral() || o.isTripleTerm() 
) )
             exception(startToken, "Illgeal object in a reified triple: %s", o);
         return o;
@@ -386,18 +388,6 @@ public abstract class LangTurtleBase extends LangBase {
         return x;
     }
 
-//    // XXX Checker.validateTriple
-//    // XXX TripleTerm
-//    private void validateTriple(Node s, Node p, Node o, String usage, Token 
token) {
-//        if ( ! (s.isURI() || s.isBlank() ) )
-//            // ReifiedTriple covered by branch.
-//            exception(token, "Subject in a %s is not a URI, blank node or a 
nested reified triple: %s", usage, s);
-//        if ( ! p.isURI() )
-//            exception(token, "Predicate in a %s is not a URI: %s", usage, p);
-//        if ( ! (o.isURI() || o.isBlank() || o.isLiteral() || 
o.isNodeTriple() ) )
-//            exception(token, "Object in a %s is not a URI, blank node, 
nested reified triple or triple term : %s", usage, o);
-//    }
-
     private Node parseTripleTerm() {
         Token entryToken = nextToken();
         Node s = ttSubject();
@@ -417,7 +407,6 @@ public abstract class LangTurtleBase extends LangBase {
 
         if ( ! lookingAt(TokenType.TILDE) )
             return profile.createBlankNode(currentGraph, line, column);
-        // XXX Check BNF
         return Reifier(s, p, o, line, column);
     }
 
@@ -434,7 +423,6 @@ public abstract class LangTurtleBase extends LangBase {
         Node reif;
         // URI or bNode
         if ( lookingAtIRIorBNode() ) {
-            // XXX   and use elsewhere : nodeURIorBLankNode()
             nextToken();
             reif = tokenAsNode(tokenReif);
         } else if ( lookingAt(LBRACKET) ) {
@@ -442,7 +430,7 @@ public abstract class LangTurtleBase extends LangBase {
             nextToken();
             Token t = peekToken();
             if ( ! lookingAt(RBRACKET) )
-                exception(peekToken(), "Bad %s in RDF triple. Expected ] after 
[", "riefier", peekToken().text());
+                exception(peekToken(), "Bad %s in RDF triple. Expected ] after 
[", "reifier", peekToken().text());
             nextToken();
             reif = profile.createBlankNode(currentGraph, t.getLine(), 
t.getColumn());
         } else {
@@ -454,18 +442,12 @@ public abstract class LangTurtleBase extends LangBase {
     }
 
     private Node ttSubject() {
-        Node node = term("subject");
-        // XXX Maybe allow but restrict later.
-        if ( node.isLiteral() )
-            exception(peekToken(), "Literals are not legal in the subject 
position.");
-        if ( node.isTripleTerm() ) {
-            exception(peekToken(), "Triple terms are not legal in the subject 
position.");
-        }
+        Node node = tripleTermSubjectObject(Posn.SUBJECT);
         return node;
     }
 
     private Node ttObject() {
-        Node node = term("object");
+        Node node = tripleTermSubjectObject(Posn.OBJECT);
         return node;
     }
 
@@ -479,7 +461,8 @@ public abstract class LangTurtleBase extends LangBase {
         return nodeTerm();
     }
 
-    // Single token terms, triple terms and reified triples.
+
+    // Single token terms, triple terms <<( ... )>> and reified triples. << 
... >>
     private Node nodeTerm() {
         if ( lookingAt(LT2) )
             return parseReifiedTriple();
@@ -489,9 +472,33 @@ public abstract class LangTurtleBase extends LangBase {
         return node;
     }
 
-    /** Any RDFTerm, including compound structures but not reified triples. */
-    // XXX RENAME
-    private Node term(String posnLabel) {
+    // Keywords 'true' and 'false'
+    private Node possibleBooleanLiteral() {
+        if ( ! lookingAt(TokenType.KEYWORD) )
+            return null;
+        Token tErr = peekToken();
+        // Location independent node words
+        String image = peekToken().getImage();
+        nextToken();
+        if ( image.equals(KW_TRUE) )
+            return NodeConst.nodeTrue;
+        if ( image.equals(KW_FALSE) )
+            return NodeConst.nodeFalse;
+        if ( image.equals(KW_A) )
+            exception(tErr, "Keyword 'a' not legal at this point");
+
+        exception(tErr, "Unrecognized keyword: " + image);
+        return null;
+    }
+
+    enum Posn {
+        SUBJECT("subject"), OBJECT("object");
+        private String label;
+        Posn(String label) { this.label = label; }
+    }
+
+    /** Any RDFTerm that can appear in a triple term subject or object 
position. */
+    private Node tripleTermSubjectObject(Posn posn) {
         if ( lookingAt(L_TRIPLE) )
             return parseTripleTerm();
 
@@ -507,20 +514,36 @@ public abstract class LangTurtleBase extends LangBase {
             nextToken();
             Token t = peekToken();
             if ( ! lookingAt(RBRACKET) )
-                exception(peekToken(), "Bad %s in RDF triple. Expected ] after 
[", posnLabel, peekToken().text());
+                exception(peekToken(), "Bad %s in RDF triple. Expected ] after 
[", posn.label, peekToken().text());
             nextToken();
             return profile.createBlankNode(currentGraph, t.getLine(), 
t.getColumn());
         }
 
+        Node n = possibleBooleanLiteral();
+        if ( n != null )
+            return n;
+
         // Single token terms
-        if ( ! lookingAt(NODE) )
-            exception(peekToken(), "Bad %s in triple term: %s", posnLabel, 
peekToken().text());
+        if ( ! lookingAt(NODE) ) {
+            exception(peekToken(), "Bad %s in triple term: %s", posn.label, 
peekToken().text());
+        }
         Node node = node();
+
+        // Further restrictions due to position.
+        switch (posn) {
+            case OBJECT->{} // None
+            case SUBJECT->{
+                if ( node.isLiteral() )
+                    exception(peekToken(), "Literals are not legal in the %s 
position.", posn.label);
+                if ( node.isTripleTerm() ) {
+                    exception(peekToken(), "Triple terms are not legal in the 
%s position.", posn.label);
+                }
+            }
+        }
         return node;
     }
 
     // Must be at least one triple.
-    //   Not reifiedTriple
     protected final void triplesSameSubject() {
         // Looking at a node.
         Node subject = subject();
@@ -578,10 +601,7 @@ public abstract class LangTurtleBase extends LangBase {
     static protected final Node nodeSameAs     = NodeConst.nodeOwlSameAs;
     static protected final Node nodeLogImplies = 
NodeFactory.createURI("http://www.w3.org/2000/10/swap/log#implies";);
 
-    // XXX verb()
-
     // [11]  verb  ::= predicate | 'a'
-    // [12]  subject ::= iri | BlankNode | collection
     // [13]  predicate ::= iri
     // and '=' (owl:sameAs),
     /** Get predicate - return null for "illegal" */
@@ -643,7 +663,6 @@ public abstract class LangTurtleBase extends LangBase {
         return n;
     }
 
-    // XXX Update for RDF 1.2
     protected final void objectList(Node subject, Node predicate) {
         for (;;) {
             // object ::=
@@ -692,29 +711,13 @@ public abstract class LangTurtleBase extends LangBase {
             Node n = node();
             return n;
         }
-
-        // Special words.
-        if ( lookingAt(TokenType.KEYWORD) ) {
-            Token tErr = peekToken();
-            // Location independent node words
-            String image = peekToken().getImage();
-            nextToken();
-            if ( image.equals(KW_TRUE) )
-                return NodeConst.nodeTrue;
-            if ( image.equals(KW_FALSE) )
-                return NodeConst.nodeFalse;
-            if ( image.equals(KW_A) )
-                exception(tErr, "Keyword 'a' not legal at this point");
-
-            exception(tErr, "Unrecognized keyword: " + image);
-        }
-
         if ( lookingAt(LT2) )
             return parseReifiedTriple();
-
         if ( lookingAt(L_TRIPLE) )
             return parseTripleTerm();
-
+        Node n = possibleBooleanLiteral();
+        if ( n != null )
+            return n;
         return triplesNodeCompound();
     }
 
diff --git 
a/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java 
b/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java
index cd243b220d..f1e00f063b 100644
--- a/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java
+++ b/jena-arq/src/test/java/org/apache/jena/riot/lang/TestLangTurtle.java
@@ -234,14 +234,25 @@ public class TestLangTurtle
 
     @Test
     public void turtle_rdf12_04() {
+        Graph graph = parse(PREFIXES, "[] rdf:reifies <<( :s :p true )>>");
+        assertEquals(1, graph.size());
+    }
+
+    public void turtle_rdf12_05() {
+        Graph graph = parse(PREFIXES, "<< :s :p false >>");
+        assertEquals(1, graph.size());
+    }
+
+    @Test
+    public void turtle_rdf12_bad_01() {
         // Triple term as subject
         parseException(ExFatal.class, PREFIXES, "<<( :s :p :o )>> :q :z ");
     }
 
     @Test
-    public void turtle_rdf12_05() {
-        // Triple term as subject
-        parseException(ExFatal.class, PREFIXES, ":a <<( :s :p :o )>> :b :c");
+    public void turtle_rdf12_bad_02() {
+        // Triple term as predicate
+        parseException(ExFatal.class, PREFIXES, ":a <<( :s :p :o )>> :b ");
     }
 
     @Test

Reply via email to