org.voltdb.parser.SQLPatternPartElement Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of voltdbclient Show documentation
Show all versions of voltdbclient Show documentation
VoltDB client interface libraries
/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see .
*/
package org.voltdb.parser;
import java.util.regex.Pattern;
import org.voltcore.logging.VoltLogger;
public class SQLPatternPartElement extends SQLPatternPart
{
//===== Private
String m_leader = null;
String m_trailer = null;
String m_separator = null;
private SQLPatternPart[] m_parts;
String m_captureLabel = null;
private static final VoltLogger COMPILER_LOG = new VoltLogger("COMPILER");
/**
* Private constructor from multiple strings
* SQLPat static factory methods should be used for element creation.
* @param strs strings used for main part of expression
*/
SQLPatternPartElement(String[] strs)
{
m_parts = new SQLPatternPart[strs.length];
for (int i = 0; i < strs.length; ++i) {
m_parts[i] = new SQLPatternPartString(strs[i]);
}
}
/**
* Private constructor from multiple elements
* SQLPat static factory methods should be used for element creation.
* @param parts pattern parts
*/
SQLPatternPartElement(SQLPatternPart... parts)
{
m_parts = parts;
}
/**
* Private constructor from a single string
* SQLPat static factory methods should be used for element creation.
* @param strs string used for main part of expression
*/
SQLPatternPartElement(String str)
{
m_parts = new SQLPatternPart[] {new SQLPatternPartString(str)};
}
//===== Part interface
@Override
public String generateExpression(int flagsAdd)
{
int flags = m_flags | flagsAdd;
StringBuilder sb = new StringBuilder();
if (m_leader != null) {
sb.append(m_leader);
}
// Need a non-capturing group when either an explicit non-capturing group is
// requested or it is optional. The only case where a non-capturing group isn't
// needed for an optional is an explicit capture without leading space.
boolean captureGroup = (flags & SQLPatternFactory.CAPTURE) != 0;
boolean explicitNonCaptureGroup = !captureGroup && (flags & SQLPatternFactory.GROUP) != 0;
boolean optional = ((flags & SQLPatternFactory.OPTIONAL) != 0);
// Suppress the leading space at this level when it should be pushed down to the child.
boolean leadingSpace = ((flags & SQLPatternFactory.LEADING_SPACE) != 0);
boolean leadingSpaceToChild = ((flags & SQLPatternFactory.ADD_LEADING_SPACE_TO_CHILD) != 0);
boolean childLeadingSpace = ((flags & SQLPatternFactory.CHILD_SPACE_SEPARATOR) != 0 ||
(leadingSpace && leadingSpaceToChild));
boolean nonCaptureGroup = (explicitNonCaptureGroup ||
(optional && (!captureGroup || leadingSpace)));
boolean innerOptional = optional && captureGroup && !nonCaptureGroup;
boolean outerOptional = optional && nonCaptureGroup;
if (nonCaptureGroup) {
sb.append("(?:");
}
if (leadingSpace && !leadingSpaceToChild) {
// Protect something like an OR sequence by using an inner group
sb.append("\\s+(?:");
}
if (captureGroup) {
if (m_captureLabel != null) {
sb.append(String.format("(?<%s>", m_captureLabel));
}
else {
sb.append("(");
}
}
for (int i = 0; i < m_parts.length; ++i) {
int flagsAddChild = 0;
if (i > 0) {
if (m_separator != null) {
sb.append(m_separator);
}
if (childLeadingSpace) {
flagsAddChild |= SQLPatternFactory.LEADING_SPACE;
}
}
else if (childLeadingSpace && leadingSpaceToChild) {
flagsAddChild |= SQLPatternFactory.LEADING_SPACE;
}
sb.append(m_parts[i].generateExpression(flagsAddChild));
}
if (captureGroup) {
sb.append(")");
}
if (innerOptional) {
sb.append("?");
}
if (leadingSpace && !leadingSpaceToChild) {
sb.append(")");
}
if (nonCaptureGroup) {
sb.append(")");
}
if (outerOptional) {
sb.append("?");
}
if (m_trailer != null) {
sb.append(m_trailer);
}
return sb.toString();
}
@Override
public void setCaptureLabel(String captureLabel)
{
m_captureLabel = captureLabel;
}
@Override
public Pattern compile(String label)
{
int reFlags = 0;
if ((m_flags & SQLPatternFactory.CASE_SENSITIVE) == 0) {
reFlags |= Pattern.CASE_INSENSITIVE;
}
if ((m_flags & SQLPatternFactory.IGNORE_NEW_LINE) == 0) {
reFlags |= Pattern.DOTALL;
}
if ((m_flags & SQLPatternFactory.SINGLE_LINE) == 0) {
reFlags |= Pattern.MULTILINE;
}
String regex = generateExpression(0);
COMPILER_LOG.debug(String.format("PATTERN: %s: %s", label, regex));
return Pattern.compile(regex, reFlags);
}
}