/* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2006. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.query.parser.serql; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.openrdf.query.parser.serql.ast.ASTProjectionElem; import org.openrdf.query.parser.serql.ast.ASTSelect; import org.openrdf.query.parser.serql.ast.ASTString; import org.openrdf.query.parser.serql.ast.ASTVar; import org.openrdf.query.parser.serql.ast.Node; import org.openrdf.query.parser.serql.ast.SyntaxTreeBuilderTreeConstants; import org.openrdf.query.parser.serql.ast.VisitorException; /** * Processes projection aliases, verifying that the specified aliases are unique * and generating aliases for the elements for which no alias has been * specified but that do require one. * * @author Arjohn Kampman */ class ProjectionAliasProcessor extends ASTVisitorBase { @Override public Object visit(ASTSelect node, Object data) throws VisitorException { // Iterate over all projection elements to retrieve the defined aliases Set<String> aliases = new HashSet<String>(); List<Node> unaliasedNodes = new ArrayList<Node>(); for (int i = 0; i < node.jjtGetNumChildren(); i++) { Node projElem = node.jjtGetChild(i); assert projElem instanceof ASTProjectionElem : "child node is not a projection element"; Object result = projElem.jjtAccept(this, aliases); if (result instanceof String) { String alias = (String)result; boolean isUnique = aliases.add(alias); if (!isUnique) { throw new VisitorException("Duplicate projection element aliases: '" + alias + "'"); } } else { unaliasedNodes.add(projElem); } } // Iterate over the unaliased nodes and generate aliases for them int aliasNo = 1; for (Node projElem : unaliasedNodes) { Node exprNode = projElem.jjtGetChild(0); if (exprNode instanceof ASTVar) { String varName = ((ASTVar)exprNode).getName(); if (!aliases.contains(varName)) { // No need to generate an alias for this element aliases.add(varName); continue; } } // Generate unique alias for projection element String alias; while (aliases.contains(alias = "_" + aliasNo++)) { // try again } aliases.add(alias); ASTString aliasNode = new ASTString(SyntaxTreeBuilderTreeConstants.JJTSTRING); aliasNode.setValue(alias); aliasNode.jjtSetParent(projElem); projElem.jjtAppendChild(aliasNode); } return data; } @Override public Object visit(ASTProjectionElem node, Object data) throws VisitorException { // Only visit alias node if (node.jjtGetNumChildren() >= 2) { return node.jjtGetChild(1).jjtAccept(this, data); } return data; } @Override public String visit(ASTString node, Object data) throws VisitorException { return node.getValue(); } }