/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Portions of this code are: * * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007. * * Licensed under the Aduna BSD-style license. */ /* * Created on Aug 21, 2011 */ package com.bigdata.rdf.sail.sparql; import org.openrdf.query.algebra.StatementPattern.Scope; import com.bigdata.rdf.internal.IV; import com.bigdata.rdf.model.BigdataValue; import com.bigdata.rdf.sail.sparql.ast.ASTBlankNode; import com.bigdata.rdf.sail.sparql.ast.ASTFalse; import com.bigdata.rdf.sail.sparql.ast.ASTGraphGraphPattern; import com.bigdata.rdf.sail.sparql.ast.ASTIRI; import com.bigdata.rdf.sail.sparql.ast.ASTNumericLiteral; import com.bigdata.rdf.sail.sparql.ast.ASTQName; import com.bigdata.rdf.sail.sparql.ast.ASTRDFLiteral; import com.bigdata.rdf.sail.sparql.ast.ASTString; import com.bigdata.rdf.sail.sparql.ast.ASTTrue; import com.bigdata.rdf.sail.sparql.ast.ASTVar; import com.bigdata.rdf.sail.sparql.ast.Node; import com.bigdata.rdf.sail.sparql.ast.VisitorException; import com.bigdata.rdf.sparql.ast.ConstantNode; import com.bigdata.rdf.sparql.ast.TermNode; import com.bigdata.rdf.sparql.ast.VarNode; /** * Base class for AST visitor impls. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @openrdf */ public abstract class BigdataASTVisitorBase extends ASTVisitorBase { protected final BigdataASTContext context; protected BigdataASTVisitorBase(final BigdataASTContext context) { this.context = context; } /** * Return the depth of the node in the parse tree. The depth is ZERO (0) if * the node does not have a parent. * * @param node * The node. * @return The depth of that node. */ final protected int depth(Node node) { int i = 0; while ((node = node.jjtGetParent()) != null) { i++; } return i; } /** * Return a white space string which may be used to indent the node to its * depth in the parse tree. * * @param node * The node. * * @return The indent string. */ final protected String indent(final Node node) { return indent(depth(node)); } /** * Returns a string that may be used to indent a dump of the nodes in the * tree. * * @param depth * The indentation depth. * * @return A string suitable for indent at that height. */ protected static String indent(final int depth) { if (depth < 0) { return ""; } return ws.substring(0, depth *2); } private static final transient String ws = " "; @SuppressWarnings("unchecked") private IV<BigdataValue, ?> makeIV(final BigdataValue value) throws VisitorException { if (value == null) throw new VisitorException("Value property not set?"); final IV<BigdataValue,?> iv = value.getIV(); if (iv == null) throw new VisitorException("IV not resolved : " + value); return iv; // IV iv = context.lexicon.getInlineIV(value); // // if (iv == null) { // // iv = (IV<BigdataValue, ?>) TermId.mockIV(VTE.valueOf(value)); // // iv.setValue(value); // // } // // return iv; } /* * Productions used by different ASTVisitor facets. */ /** * Note: openrdf uses the {@link BlankNodeVarProcessor} create anonymous * variables from blank nodes and then flags those as anonymous variables in * this step. */ @Override final public VarNode visit(final ASTVar node, final Object data) throws VisitorException { final VarNode var = new VarNode(node.getName()); if (node.isAnonymous()) var.setAnonymous(true); return var; } @Override final public Object visit(final ASTQName node, final Object data) throws VisitorException { throw new VisitorException( "QNames must be resolved before building the query model"); } @Override final public Object visit(ASTBlankNode node, Object data) throws VisitorException { throw new VisitorException( "Blank nodes must be replaced with variables before building the query model"); } @Override final public ConstantNode visit(final ASTIRI node, Object data) throws VisitorException { return new ConstantNode(makeIV((BigdataValue)node.getRDFValue())); } @Override final public ConstantNode visit(final ASTRDFLiteral node, Object data) throws VisitorException { return new ConstantNode(makeIV((BigdataValue) node.getRDFValue())); } @Override final public ConstantNode visit(ASTNumericLiteral node, Object data) throws VisitorException { return new ConstantNode(makeIV((BigdataValue) node.getRDFValue())); } @Override final public ConstantNode visit(ASTTrue node, Object data) throws VisitorException { return new ConstantNode(makeIV((BigdataValue) node.getRDFValue())); } @Override final public ConstantNode visit(ASTFalse node, Object data) throws VisitorException { return new ConstantNode(makeIV((BigdataValue) node.getRDFValue())); } @Override final public String visit(ASTString node, Object data) throws VisitorException { return node.getValue(); } /** * Builds a fresh {@link GroupGraphPattern} that inherits the scope * for the given node. This is done by looking up the scope of the given * node by following its ancestor chain, to identify whether the node * has some named graph ancestors. If so, the scope from the enclosing * named graph ancestor is copied over, otherwise we're in default context. * * @param n * @return */ protected GroupGraphPattern scopedGroupGraphPattern(Node n) throws VisitorException { // extract the enclosing ASTGraphGraphPattern, if any ASTGraphGraphPattern scopePattern = firstASTGraphGraphAncestor(n); // if we're in a ASTGraphGraphPattern scope (for instance, // this is the case for a subquery enclosed in a graph section, // so we need to inherit that scope (see e.g. #832) if (scopePattern!=null) { Node child = scopePattern.jjtGetChild(0); if (child!=null) { final TermNode s = (TermNode) scopePattern.jjtGetChild(0).jjtAccept(this, null); if (s!=null) return new GroupGraphPattern(s, Scope.NAMED_CONTEXTS); } } // otherwise, we're in default scope return new GroupGraphPattern(); } /** * Returns the enclosing ASTGraphGraphPattern ancestor-or-self for the * given node, or null if none exists. * * @param node node at which to start lookup * @return first enclosing {@link ASTGraphGraphPattern} ancestor, if any, * null otherwise */ protected ASTGraphGraphPattern firstASTGraphGraphAncestor(Node node) { if (node==null) return null; if (node instanceof ASTGraphGraphPattern) return (ASTGraphGraphPattern)node; return firstASTGraphGraphAncestor(node.jjtGetParent()); } }