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


The following commit(s) were added to refs/heads/main by this push:
     new 8cc0a5eb8b GH-2102: Parse and accept [], with warning
8cc0a5eb8b is described below

commit 8cc0a5eb8b147b8fc300cde461ce8bbe1cfcdc05
Author: Andy Seaborne <[email protected]>
AuthorDate: Fri Dec 1 11:08:45 2023 +0000

    GH-2102: Parse and accept [], with warning
---
 .../apache/jena/sparql/lang/QueryParserBase.java   | 397 +++++++++++----------
 .../org/apache/jena/sparql/syntax/TS_Syntax.java   |   3 +-
 .../apache/jena/sparql/syntax/TestQueryParser.java |  87 +++++
 3 files changed, 298 insertions(+), 189 deletions(-)

diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/lang/QueryParserBase.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/lang/QueryParserBase.java
index 0cd59e4327..75920d7f05 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/lang/QueryParserBase.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/lang/QueryParserBase.java
@@ -18,91 +18,94 @@
 
 package org.apache.jena.sparql.lang;
 
-import java.math.BigInteger ;
-import java.util.HashSet ;
-import java.util.Set ;
-
-import org.apache.jena.atlas.AtlasException ;
-import org.apache.jena.atlas.lib.EscapeStr ;
-import org.apache.jena.atlas.logging.Log ;
-import org.apache.jena.datatypes.RDFDatatype ;
-import org.apache.jena.datatypes.TypeMapper ;
-import org.apache.jena.datatypes.xsd.XSDDatatype ;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.graph.NodeFactory ;
-import org.apache.jena.graph.Triple ;
+import java.math.BigInteger;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.jena.atlas.AtlasException;
+import org.apache.jena.atlas.lib.EscapeStr;
+import org.apache.jena.atlas.logging.Log;
+import org.apache.jena.datatypes.RDFDatatype;
+import org.apache.jena.datatypes.TypeMapper;
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.graph.Triple;
 import org.apache.jena.irix.IRIException;
-import org.apache.jena.query.ARQ ;
-import org.apache.jena.query.QueryParseException ;
+import org.apache.jena.irix.IRIx;
+import org.apache.jena.irix.RelativeIRIException;
+import org.apache.jena.query.ARQ;
+import org.apache.jena.query.QueryParseException;
 import org.apache.jena.riot.lang.extra.LangParserLib;
-import org.apache.jena.riot.system.ErrorHandler ;
-import org.apache.jena.riot.system.ErrorHandlerFactory ;
-import org.apache.jena.riot.system.RiotLib ;
-import org.apache.jena.sparql.ARQInternalErrorException ;
-import org.apache.jena.sparql.core.Prologue ;
-import org.apache.jena.sparql.core.TriplePath ;
-import org.apache.jena.sparql.core.Var ;
+import org.apache.jena.riot.system.Checker;
+import org.apache.jena.riot.system.ErrorHandler;
+import org.apache.jena.riot.system.ErrorHandlerFactory;
+import org.apache.jena.riot.system.RiotLib;
+import org.apache.jena.sparql.ARQInternalErrorException;
+import org.apache.jena.sparql.core.Prologue;
+import org.apache.jena.sparql.core.TriplePath;
+import org.apache.jena.sparql.core.Var;
 import org.apache.jena.sparql.expr.*;
-import org.apache.jena.sparql.graph.NodeConst ;
-import org.apache.jena.sparql.modify.request.QuadAccSink ;
+import org.apache.jena.sparql.graph.NodeConst;
+import org.apache.jena.sparql.modify.request.QuadAccSink;
 import org.apache.jena.sparql.path.P_Link;
-import org.apache.jena.sparql.path.Path ;
-import org.apache.jena.sparql.syntax.* ;
-import org.apache.jena.vocabulary.RDF ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
+import org.apache.jena.sparql.path.Path;
+import org.apache.jena.sparql.syntax.*;
+import org.apache.jena.vocabulary.RDF;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /** Base class parsers, mainly SPARQL related */
 public class QueryParserBase
 {
     // NodeConst
-    protected final Node XSD_TRUE       = NodeConst.nodeTrue ;
-    protected final Node XSD_FALSE      = NodeConst.nodeFalse ;
+    protected final Node XSD_TRUE       = NodeConst.nodeTrue;
+    protected final Node XSD_FALSE      = NodeConst.nodeFalse;
 
-    protected final Node nRDFtype       = NodeConst.nodeRDFType ;
+    protected final Node nRDFtype       = NodeConst.nodeRDFType;
 
-    protected final Node nRDFnil        = NodeConst.nodeNil ;
-    protected final Node nRDFfirst      = NodeConst.nodeFirst ;
-    protected final Node nRDFrest       = NodeConst.nodeRest ;
+    protected final Node nRDFnil        = NodeConst.nodeNil;
+    protected final Node nRDFfirst      = NodeConst.nodeFirst;
+    protected final Node nRDFrest       = NodeConst.nodeRest;
 
-    protected final Node nRDFsubject    = RDF.Nodes.subject ;
-    protected final Node nRDFpredicate  = RDF.Nodes.predicate ;
-    protected final Node nRDFobject     = RDF.Nodes.object ;
+    protected final Node nRDFsubject    = RDF.Nodes.subject;
+    protected final Node nRDFpredicate  = RDF.Nodes.predicate;
+    protected final Node nRDFobject     = RDF.Nodes.object;
 
     // ----
     // Graph patterns, true; in templates, false.
-    private boolean bNodesAreVariables = true ;
+    private boolean bNodesAreVariables = true;
     // In DELETE, false.
-    private boolean bNodesAreAllowed = true ;
+    private boolean bNodesAreAllowed = true;
 
     // label => bNode for construct templates patterns
     @SuppressWarnings("deprecation")
-    final LabelToNodeMap bNodeLabels = LabelToNodeMap.createBNodeMap() ;
+    final LabelToNodeMap bNodeLabels = LabelToNodeMap.createBNodeMap();
 
     // label => bNode (as variable) for graph patterns
-    final LabelToNodeMap anonVarLabels = LabelToNodeMap.createVarMap() ;
+    final LabelToNodeMap anonVarLabels = LabelToNodeMap.createVarMap();
 
     // This is the map used allocate blank node labels during parsing.
     // 1/ It is different between CONSTRUCT and the query pattern
     // 2/ Each BasicGraphPattern is a scope for blank node labels so each
     //    BGP causes the map to be cleared at the start of the BGP
 
-    protected LabelToNodeMap activeLabelMap = anonVarLabels ;
-    protected Set<String> previousLabels = new HashSet<>() ;
+    protected LabelToNodeMap activeLabelMap = anonVarLabels;
+    protected Set<String> previousLabels = new HashSet<>();
 
     // Aggregates are only allowed in places where grouping can happen.
     // e.g. SELECT clause but not a FILTER.
-    private boolean allowAggregatesInExpressions = false ;
-    private int     aggregateDepth               = 0 ;
+    private boolean allowAggregatesInExpressions = false;
+    private int     aggregateDepth               = 0;
 
-    //LabelToNodeMap listLabelMap = new LabelToNodeMap(true, new 
VarAlloc("L")) ;
+    //LabelToNodeMap listLabelMap = new LabelToNodeMap(true, new 
VarAlloc("L"));
     // ----
 
     public QueryParserBase() {}
 
-    protected Prologue prologue ;
-    public void setPrologue(Prologue prologue) { this.prologue = prologue ; }
-    public Prologue getPrologue() { return prologue ; }
+    protected Prologue prologue;
+    public void setPrologue(Prologue prologue) { this.prologue = prologue; }
+    public Prologue getPrologue() { return prologue; }
 
     protected void setBase(String iriStr, int line, int column) {
         if ( isBNodeIRI(iriStr) )
@@ -118,27 +121,27 @@ public class QueryParserBase
     }
 
     protected void setInConstructTemplate(boolean b) {
-        setBNodesAreVariables(!b) ;
+        setBNodesAreVariables(!b);
     }
 
-    protected boolean getBNodesAreVariables()   { return bNodesAreVariables ; }
+    protected boolean getBNodesAreVariables()   { return bNodesAreVariables; }
 
     protected void setBNodesAreVariables(boolean bNodesAreVariables) {
-        this.bNodesAreVariables = bNodesAreVariables ;
+        this.bNodesAreVariables = bNodesAreVariables;
         if ( bNodesAreVariables )
-            activeLabelMap = anonVarLabels ;
+            activeLabelMap = anonVarLabels;
         else
-            activeLabelMap = bNodeLabels ;
+            activeLabelMap = bNodeLabels;
     }
 
-    protected boolean getBNodesAreAllowed()   { return bNodesAreAllowed ; }
+    protected boolean getBNodesAreAllowed()   { return bNodesAreAllowed; }
 
     protected void setBNodesAreAllowed(boolean bNodesAreAllowed) {
-        this.bNodesAreAllowed = bNodesAreAllowed ;
+        this.bNodesAreAllowed = bNodesAreAllowed;
     }
 
     protected boolean getAllowAggregatesInExpressions() {
-        return allowAggregatesInExpressions ;
+        return allowAggregatesInExpressions;
     }
 
     protected void setAllowAggregatesInExpressions(boolean 
allowAggregatesInExpressions) {
@@ -153,41 +156,41 @@ public class QueryParserBase
     protected Element compressGroupOfOneGroup(ElementGroup elg) {
         // remove group of one group.
         if ( elg.size() == 1 ) {
-            Element e1 = elg.get(0) ;
+            Element e1 = elg.get(0);
             if ( e1 instanceof ElementGroup )
-                return e1 ;
+                return e1;
         }
-        return elg ;
+        return elg;
     }
 
     protected Node createLiteralInteger(String lexicalForm) {
-        return NodeFactory.createLiteral(lexicalForm, XSDDatatype.XSDinteger) ;
+        return NodeFactory.createLiteral(lexicalForm, XSDDatatype.XSDinteger);
     }
 
     protected Node createLiteralDouble(String lexicalForm) {
-        return NodeFactory.createLiteral(lexicalForm, XSDDatatype.XSDdouble) ;
+        return NodeFactory.createLiteral(lexicalForm, XSDDatatype.XSDdouble);
     }
 
     protected Node createLiteralDecimal(String lexicalForm) {
-        return NodeFactory.createLiteral(lexicalForm, XSDDatatype.XSDdecimal) ;
+        return NodeFactory.createLiteral(lexicalForm, XSDDatatype.XSDdecimal);
     }
 
     protected Node stripSign(Node node) {
         if ( !node.isLiteral() )
-            return node ;
-        String lex = node.getLiteralLexicalForm() ;
-        String lang = node.getLiteralLanguage() ;
-        RDFDatatype dt = node.getLiteralDatatype() ;
+            return node;
+        String lex = node.getLiteralLexicalForm();
+        String lang = node.getLiteralLanguage();
+        RDFDatatype dt = node.getLiteralDatatype();
 
         if ( !lex.startsWith("-") && !lex.startsWith("+") )
-            throw new ARQInternalErrorException("Literal does not start with a 
sign: " + lex) ;
+            throw new ARQInternalErrorException("Literal does not start with a 
sign: " + lex);
 
-        lex = lex.substring(1) ;
-        return NodeFactory.createLiteral(lex, lang, dt) ;
+        lex = lex.substring(1);
+        return NodeFactory.createLiteral(lex, lang, dt);
     }
 
     protected void checkString(String string, int line, int column) {
-        for ( int i = 0 ; i < string.length() ; i++ ) {
+        for ( int i = 0; i < string.length(); i++ ) {
             // Not "codePointAt" which does surrogate processing.
             char ch = string.charAt(i);
             // Check surrogate pairs are pairs.
@@ -206,55 +209,55 @@ public class QueryParserBase
     }
 
     protected Node createLiteral(String lexicalForm, String langTag, String 
datatypeURI) {
-        Node n = null ;
+        Node n = null;
         // Can't have type and lang tag in parsing.
         if ( datatypeURI != null ) {
-            RDFDatatype dType = 
TypeMapper.getInstance().getSafeTypeByName(datatypeURI) ;
-            n = NodeFactory.createLiteral(lexicalForm, dType) ;
+            RDFDatatype dType = 
TypeMapper.getInstance().getSafeTypeByName(datatypeURI);
+            n = NodeFactory.createLiteral(lexicalForm, dType);
         } else if ( langTag != null && !langTag.isEmpty() )
-            n = NodeFactory.createLiteral(lexicalForm, langTag) ;
+            n = NodeFactory.createLiteral(lexicalForm, langTag);
         else
-            n = NodeFactory.createLiteral(lexicalForm) ;
-        return n ;
+            n = NodeFactory.createLiteral(lexicalForm);
+        return n;
     }
 
     protected long integerValue(String s) {
         try {
             if ( s.startsWith("+") )
-                s = s.substring(1) ;
+                s = s.substring(1);
             if ( s.startsWith("0x") ) {
                 // Hex
-                s = s.substring(2) ;
-                return Long.parseLong(s, 16) ;
+                s = s.substring(2);
+                return Long.parseLong(s, 16);
             }
-            return Long.parseLong(s) ;
+            return Long.parseLong(s);
         }
         catch (NumberFormatException ex) {
             try {
                 // Possible too large for a long.
-                BigInteger integer = new BigInteger(s) ;
-                throwParseException("Number '" + s + "' is a valid number but 
can't not be stored in a long") ;
+                BigInteger integer = new BigInteger(s);
+                throwParseException("Number '" + s + "' is a valid number but 
can't not be stored in a long");
             }
             catch (NumberFormatException ex2) {}
-            throw new QueryParseException(ex, -1, -1) ;
+            throw new QueryParseException(ex, -1, -1);
         }
     }
 
     protected double doubleValue(String s) {
         if ( s.startsWith("+") )
-            s = s.substring(1) ;
-        double valDouble = Double.parseDouble(s) ;
-        return valDouble ;
+            s = s.substring(1);
+        double valDouble = Double.parseDouble(s);
+        return valDouble;
     }
 
     /** Remove first and last characters (e.g. ' or "") from a string */
     protected static String stripQuotes(String s) {
-        return s.substring(1, s.length() - 1) ;
+        return s.substring(1, s.length() - 1);
     }
 
     /** Remove first 3 and last 3 characters (e.g. ''' or """) from a string */
     protected static String stripQuotes3(String s) {
-        return s.substring(3, s.length() - 3) ;
+        return s.substring(3, s.length() - 3);
     }
 
     /** remove the first n characters from the string */
@@ -263,73 +266,91 @@ public class QueryParserBase
     }
 
     protected Var createVariable(String s, int line, int column) {
-        s = s.substring(1) ; // Drop the marker
+        s = s.substring(1); // Drop the marker
 
         // This is done by the parser input stream nowadays.
-        // s = unescapeCodePoint(s, line, column) ;
+        // s = unescapeCodePoint(s, line, column);
         // Check \ u did not put in any illegals.
-        return Var.alloc(s) ;
+        return Var.alloc(s);
     }
 
     // ---- IRIs and Nodes
 
     protected String resolveQuotedIRI(String iriStr, int line, int column) {
-        iriStr = stripQuotes(iriStr) ;
+        iriStr = stripQuotes(iriStr);
         iriStr = unescapeUnicode(iriStr, line, column);
-        return resolveIRI(iriStr, line, column) ;
+        return resolveIRI(iriStr, line, column);
     }
 
-    public static final String ParserLoggerName = "SPARQL" ;
-    private static Logger parserLog = 
LoggerFactory.getLogger(ParserLoggerName) ;
-    private static ErrorHandler errorHandler = 
ErrorHandlerFactory.errorHandlerStd(parserLog) ;
+    public static final String ParserLoggerName = "SPARQL";
+    public static Logger parserLog = LoggerFactory.getLogger(ParserLoggerName);
+    private static final ErrorHandler errorHandler = 
ErrorHandlerFactory.errorHandlerStd(parserLog);
 
     protected String resolveIRI(String iriStr, int line, int column) {
         if ( isBNodeIRI(iriStr) )
-            return iriStr ;
-
-        if ( getPrologue() != null ) {
-            if ( getPrologue().getBase() != null ) {
-                try {
-                    iriStr = 
getPrologue().getBase().resolve(iriStr).toString();
-                } catch (IRIException ex) {
-                    errorHandler.error("Bad IRI: '"+iriStr+"': 
"+ex.getMessage(), line, column);
-                }
-            }
+            return iriStr;
+        if ( getPrologue() == null )
+            return iriStr;
+        if ( getPrologue().getBase() == null )
+            return iriStr;
+        IRIx irix = resolveIRIx(iriStr, line, column);
+        return irix.toString();
+    }
+
+    private IRIx resolveIRIx(String iriStr, long line, long col) {
+        // Aligns with ParserProfileStd.internalMakeIRI
+        // Hard to do a meaning DRY because SPARQL works in strings
+        // where as ParserProfile works in IRix.
+        if ( iriStr.contains(" ") ) {
+            // Specific check for spaces.
+            errorHandler.warning("Bad IRI: <" + iriStr + "> Spaces are not 
legal in URIs/IRIs.", line, col);
+            return IRIx.createAny(iriStr);
+        }
+        try {
+            IRIx resolvedIRIx = getPrologue().getBase().resolve(iriStr);
+            return resolvedIRIx;
+        } catch (RelativeIRIException ex ) {
+            errorHandler.error("Relative IRI: " + iriStr, line, col);
+            return IRIx.createAny(iriStr);
+        } catch (IRIException ex) {
+            // Same code as Checker.iriViolations
+            String msg = ex.getMessage();
+            Checker.iriViolationMessage(iriStr, true, msg, line, col, 
errorHandler);
+            return IRIx.createAny(iriStr);
         }
-        return iriStr ;
     }
 
     protected String resolvePName(String prefixedName, int line, int column) {
         // It's legal.
-        int idx = prefixedName.indexOf(':') ;
+        int idx = prefixedName.indexOf(':');
 
         // -- Escapes in local name
-        String prefix = prefixedName.substring(0, idx) ;
-        String local = prefixedName.substring(idx + 1) ;
-        local = unescapePName(local, line, column) ;
-        prefixedName = prefix + ":" + local ;
+        String prefix = prefixedName.substring(0, idx);
+        String local = prefixedName.substring(idx + 1);
+        local = unescapePName(local, line, column);
+        prefixedName = prefix + ":" + local;
         // --
 
-        String s = getPrologue().expandPrefixedName(prefixedName) ;
+        String s = getPrologue().expandPrefixedName(prefixedName);
         if ( s == null ) {
             if ( ARQ.isTrue(ARQ.fixupUndefinedPrefixes) )
-                return RiotLib.fixupPrefixes.apply(prefixedName) ;
-            throwParseException("Unresolved prefixed name: " + prefixedName, 
line, column) ;
+                return RiotLib.fixupPrefixes.apply(prefixedName);
+            throwParseException("Unresolved prefixed name: " + prefixedName, 
line, column);
         }
-        return s ;
+        return s;
     }
 
-    private boolean skolomizedBNodes = ARQ.isTrue(ARQ.constantBNodeLabels) ;
+    private boolean skolomizedBNodes = ARQ.isTrue(ARQ.constantBNodeLabels);
 
     protected Node createNode(String iri) {
         if ( skolomizedBNodes )
-            return RiotLib.createIRIorBNode(iri) ;
+            return RiotLib.createIRIorBNode(iri);
         else
-            return NodeFactory.createURI(iri) ;
+            return NodeFactory.createURI(iri);
     }
 
     protected boolean isBNodeIRI(String iri) {
-        return skolomizedBNodes && RiotLib.isBNodeIRI(iri) ;
+        return skolomizedBNodes && RiotLib.isBNodeIRI(iri);
     }
 
     // -------- Basic Graph Patterns and Blank Node label scopes
@@ -338,10 +359,10 @@ public class QueryParserBase
     // but not by other graph patterns.
 
     protected void startBasicGraphPattern()
-    { activeLabelMap.clear() ; }
+    { activeLabelMap.clear(); }
 
     protected void endBasicGraphPattern()
-    { previousLabels.addAll(activeLabelMap.getLabels()) ; }
+    { previousLabels.addAll(activeLabelMap.getLabels()); }
 
     protected void startTriplesBlock()
     { }
@@ -351,43 +372,43 @@ public class QueryParserBase
 
     // On entry to a new group, the current BGP is ended.
     protected void startGroup(ElementGroup elg) {
-        endBasicGraphPattern() ;
-        startBasicGraphPattern() ;
+        endBasicGraphPattern();
+        startBasicGraphPattern();
     }
 
     protected void endGroup(ElementGroup elg) {
-        endBasicGraphPattern() ;
+        endBasicGraphPattern();
     }
 
     // --------
 
     protected void checkConcrete(Node n, int line, int column) {
         if ( ! n.isConcrete() )
-            throwParseException("Term is not concrete: "+n, line, column) ;
+            throwParseException("Term is not concrete: "+n, line, column);
     }
 
     // BNode from a list
 //    protected Node createListNode()
-//    { return listLabelMap.allocNode() ; }
+//    { return listLabelMap.allocNode(); }
 
-    protected Node createListNode(int line, int column) { return 
createBNode(line, column) ; }
+    protected Node createListNode(int line, int column) { return 
createBNode(line, column); }
 
     // Unlabelled bNode.
     protected Node createBNode(int line, int column) {
         if ( !bNodesAreAllowed )
-            throwParseException("Blank nodes not allowed in DELETE templates", 
line, column) ;
-        return activeLabelMap.allocNode() ;
+            throwParseException("Blank nodes not allowed in DELETE templates", 
line, column);
+        return activeLabelMap.allocNode();
     }
 
     // Labelled bNode.
     protected Node createBNode(String label, int line, int column) {
         if ( !bNodesAreAllowed )
-            throwParseException("Blank nodes not allowed in DELETE templates: 
" + label, line, column) ;
+            throwParseException("Blank nodes not allowed in DELETE templates: 
" + label, line, column);
         if ( previousLabels.contains(label) )
-            throwParseException("Blank node label reuse not allowed at this 
point: " + label, line, column) ;
+            throwParseException("Blank node label reuse not allowed at this 
point: " + label, line, column);
 
-        // label = unescapeCodePoint(label, line, column) ;
-        return activeLabelMap.asNode(label) ;
+        // label = unescapeCodePoint(label, line, column);
+        return activeLabelMap.asNode(label);
     }
 
     protected Node preConditionAnnotation(Node s, Node p, Path path, Node o, 
int line, int column) {
@@ -395,7 +416,7 @@ public class QueryParserBase
             return p;
         if ( path instanceof P_Link )
             return ((P_Link)path).getNode();
-        throwParseException("Only simple paths allowed with annotation 
syntax", line, column) ;
+        throwParseException("Only simple paths allowed with annotation 
syntax", line, column);
         return null;
     }
 
@@ -404,68 +425,68 @@ public class QueryParserBase
     }
 
     protected Expr createExprExists(Element element) {
-        return new E_Exists(element) ;
+        return new E_Exists(element);
     }
 
     protected Expr createExprNotExists(Element element) {
         // Could negate here.
-        return new E_NotExists(element) ;
+        return new E_NotExists(element);
     }
 
     // Convert a parser token, which includes the final ":", to a prefix name.
     protected String fixupPrefix(String prefix, int line, int column) {
         // \ u processing!
         if ( prefix.endsWith(":") )
-            prefix = prefix.substring(0, prefix.length() - 1) ;
-        return prefix ;
+            prefix = prefix.substring(0, prefix.length() - 1);
+        return prefix;
     }
 
     protected void setAccGraph(QuadAccSink acc, Node gn) {
-        acc.setGraph(gn) ;
+        acc.setGraph(gn);
     }
 
     protected void insert(TripleCollector acc, Node s, Node p, Node o) {
-        acc.addTriple(Triple.create(s, p, o)) ;
+        acc.addTriple(Triple.create(s, p, o));
     }
 
     protected void insert(TripleCollectorMark acc, int index, Node s, Node p, 
Node o) {
-        acc.addTriple(index, Triple.create(s, p, o)) ;
+        acc.addTriple(index, Triple.create(s, p, o));
     }
 
     protected void insert(TripleCollector acc, Node s, Node p, Path path, Node 
o) {
         if ( p == null )
-            acc.addTriplePath(new TriplePath(s, path, o)) ;
+            acc.addTriplePath(new TriplePath(s, path, o));
         else
-            acc.addTriple(Triple.create(s, p, o)) ;
+            acc.addTriple(Triple.create(s, p, o));
     }
 
     protected void insert(TripleCollectorMark acc, int index, Node s, Node p, 
Path path, Node o) {
         if ( p == null )
-            acc.addTriplePath(index, new TriplePath(s, path, o)) ;
+            acc.addTriplePath(index, new TriplePath(s, path, o));
         else
-            acc.addTriple(index, Triple.create(s, p, o)) ;
+            acc.addTriple(index, Triple.create(s, p, o));
     }
 
     protected void insert(TripleCollector target, ElementPathBlock source) {
         for ( TriplePath path : source.getPattern() ) {
             if ( path.isTriple() ) {
-                target.addTriple(path.asTriple()) ;
+                target.addTriple(path.asTriple());
             } else {
-                target.addTriplePath(path) ;
+                target.addTriplePath(path);
             }
         }
     }
 
     protected Expr asExpr(Node n) {
-        return ExprLib.nodeToExpr(n) ;
+        return ExprLib.nodeToExpr(n);
     }
 
     protected Expr asExprNoSign(Node n) {
-        String lex = n.getLiteralLexicalForm() ;
-        String lang = n.getLiteralLanguage() ;
-        String dtURI = n.getLiteralDatatypeURI() ;
-        n = createLiteral(lex, lang, dtURI) ;
-        return ExprLib.nodeToExpr(n) ;
+        String lex = n.getLiteralLexicalForm();
+        String lang = n.getLiteralLanguage();
+        String dtURI = n.getLiteralDatatypeURI();
+        n = createLiteral(lex, lang, dtURI);
+        return ExprLib.nodeToExpr(n);
     }
 
     // Makers of functions that need more than just a simple "new E_...".
@@ -504,28 +525,28 @@ public class QueryParserBase
     // Utilities to remove escapes in strings.
 
     /*package-testing*/ static String unescapeStr(String s)
-    { return unescapeStr(s, -1, -1) ; }
+    { return unescapeStr(s, -1, -1); }
 //
 //    public static String unescapeCodePoint(String s)
-//    { return unescape(s, '\\', true, 1, 1) ; }
+//    { return unescape(s, '\\', true, 1, 1); }
 //
 //    protected String unescapeCodePoint(String s, int line, int column)
-//    { return unescape(s, '\\', true, line, column) ; }
+//    { return unescape(s, '\\', true, line, column); }
 
 
     // Do we need the line/column versions?
     // Why not catch exceptions and comvert to  QueryParseException
 
     protected static String unescapeStr(String s, int line, int column)
-    { return unescape(s, '\\', false, line, column) ; }
+    { return unescape(s, '\\', false, line, column); }
 
     // Worker function
     protected static String unescape(String s, char escape, boolean 
pointCodeOnly, int line, int column) {
         try {
-            return EscapeStr.unescape(s, escape, pointCodeOnly) ;
+            return EscapeStr.unescape(s, escape, pointCodeOnly);
         } catch (AtlasException ex) {
-            throwParseException(ex.getMessage(), line, column) ;
-            return null ;
+            throwParseException(ex.getMessage(), line, column);
+            return null;
         }
     }
 
@@ -534,40 +555,40 @@ public class QueryParserBase
     }
 
     protected static String unescapePName(String s, int line, int column) {
-        char escape = '\\' ;
-        int idx = s.indexOf(escape) ;
+        char escape = '\\';
+        int idx = s.indexOf(escape);
 
         if ( idx == -1 )
-            return s ;
+            return s;
 
-        int len = s.length() ;
-        StringBuilder sb = new StringBuilder() ;
+        int len = s.length();
+        StringBuilder sb = new StringBuilder();
 
-        for ( int i = 0 ; i < len ; i++ ) {
-            char ch = s.charAt(i) ;
+        for ( int i = 0; i < len; i++ ) {
+            char ch = s.charAt(i);
             // Keep line and column numbers.
             switch (ch) {
                 case '\n' :
                 case '\r' :
-                    line++ ;
-                    column = 1 ;
-                    break ;
+                    line++;
+                    column = 1;
+                    break;
                 default :
-                    column++ ;
-                    break ;
+                    column++;
+                    break;
             }
 
             if ( ch != escape ) {
-                sb.append(ch) ;
-                continue ;
+                sb.append(ch);
+                continue;
             }
 
             // Escape
             if ( i >= s.length() - 1 )
-                throwParseException("Illegal escape at end of string", line, 
column) ;
-            char ch2 = s.charAt(i + 1) ;
-            column = column + 1 ;
-            i = i + 1 ;
+                throwParseException("Illegal escape at end of string", line, 
column);
+            char ch2 = s.charAt(i + 1);
+            column = column + 1;
+            i = i + 1;
 
             switch (ch2) {   // PN_LOCAL_ESC
                 case '_' :
@@ -591,24 +612,24 @@ public class QueryParserBase
                 case '#' :
                 case '@' :
                 case '%' :
-                    sb.append(ch2) ;
-                    break ;
+                    sb.append(ch2);
+                    break;
                 default :
-                    throwParseException("Illegal prefix name escape: " + ch2, 
line, column) ;
+                    throwParseException("Illegal prefix name escape: " + ch2, 
line, column);
             }
         }
-        return sb.toString() ;
+        return sb.toString();
     }
 
     protected void warnDeprecation(String msg) {
-        Log.warn(this, msg) ;
+        Log.warn(this, msg);
     }
 
     public static void throwParseException(String msg, int line, int column) {
-        throw new QueryParseException("Line " + line + ", column " + column + 
": " + msg, line, column) ;
+        throw new QueryParseException("Line " + line + ", column " + column + 
": " + msg, line, column);
     }
 
     public static void throwParseException(String msg) {
-        throw new QueryParseException(msg, -1, -1) ;
+        throw new QueryParseException(msg, -1, -1);
     }
 }
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TS_Syntax.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TS_Syntax.java
index b01904ce6a..21053ce632 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TS_Syntax.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TS_Syntax.java
@@ -27,7 +27,8 @@ import org.junit.runners.Suite.SuiteClasses ;
 
 @RunWith(Suite.class)
 @SuiteClasses( {
-    TestSerialization.class
+    TestQueryParser.class
+    , TestSerialization.class
     , TestQueryOps.class
     , TestSyntaxTransform.class
     , TestFlattenSyntax.class
diff --git 
a/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TestQueryParser.java 
b/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TestQueryParser.java
new file mode 100644
index 0000000000..8e25334fc2
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/syntax/TestQueryParser.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.syntax;
+
+import org.apache.jena.atlas.logging.LogCtl;
+import org.apache.jena.query.QueryFactory;
+import org.apache.jena.query.QueryParseException;
+import org.apache.jena.sparql.lang.QueryParserBase;
+import org.junit.Test;
+import org.slf4j.Logger;
+
+/**
+ * Query parsing is primarily tested by the scripts in the test suite.
+ * This class adds a few tests that are more conveniently done
+ * in code rather than scripts.
+ */
+public class TestQueryParser {
+    private static final Logger loggerSPARQL = QueryParserBase.parserLog;
+
+    private static void silent(Runnable action) {
+        LogCtl.withLevel(loggerSPARQL, "fatal", action);
+    }
+
+    @Test public void syntax_uri_brackets_1() {
+        testParseIRIs("<http://example/#[]>");
+    }
+
+    @Test public void syntax_uri_brackets_2() {
+        testParseIRIs("<http://example/abc[]>");
+    }
+
+    @Test public void syntax_uri_brackets_3() {
+        testParseIRIs("<http://[::1]/abc>");
+    }
+
+    @Test(expected = QueryParseException.class)
+    public void syntax_uri_brace_1() {
+        testParseIRIs("<http://example/{}>");
+    }
+
+    @Test(expected = QueryParseException.class)
+    public void syntax_uri_brace_2() {
+        testParseIRIs("<http://example/#{}>");
+    }
+
+    @Test(expected = QueryParseException.class)
+    public void syntax_uri_space_1() {
+        testParseIRIs("<http://example/abc def>");
+    }
+
+    @Test(expected = QueryParseException.class)
+    public void syntax_uri_space_2() {
+        testParseIRIs("<http://example/abc?q= def>");
+    }
+
+    @Test(expected = QueryParseException.class)
+    public void syntax_uri_space_3() {
+        testParseIRIs("< http://example/abc>");
+    }
+
+    @Test(expected = QueryParseException.class)
+    public void syntax_uri_space_4() {
+        testParseIRIs("<http://example/abc >");
+    }
+
+    // Test that a URI string can be used in Turtle data
+    // and in SPARQL in the same way.
+    public static void testParseIRIs(String string) {
+        silent(()->QueryFactory.create("SELECT * { "+string+" a 
<http://example/TYPE> }"));
+    }
+}

Reply via email to