From 73be22254a780ca6302c5ed0ddcc6713177edf67 Mon Sep 17 00:00:00 2001 From: Julian Hyde Date: Mon, 23 Nov 2020 21:44:23 -0800 Subject: [PATCH] Refactor SqlParserPos Add private class PosBuilder to allow lists or arrays of positions to be summed without creating intermediate collections. Nullness is also more transparent. --- .../org/apache/calcite/sql/SqlOperator.java | 3 +- .../sql/fun/SqlPosixRegexOperator.java | 2 +- .../org/apache/calcite/sql/parser/Span.java | 9 +- .../calcite/sql/parser/SqlParserPos.java | 203 +++++++++--------- 4 files changed, 106 insertions(+), 111 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java index 2bbebf1a23b1..50109a1d19a3 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java @@ -42,7 +42,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.dataflow.qual.Pure; -import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.function.Supplier; @@ -274,7 +273,7 @@ public SqlCall createCall( @Nullable SqlLiteral functionQualifier, SqlParserPos pos, @Nullable SqlNode... operands) { - pos = pos.plusAll(Arrays.asList(operands)); + pos = pos.plusAll(operands); return new SqlBasicCall(this, operands, pos, false, functionQualifier); } diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java index 96d1281bf93e..e57b5752b8da 100644 --- a/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java +++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlPosixRegexOperator.java @@ -84,7 +84,7 @@ public class SqlPosixRegexOperator extends SqlBinaryOperator { @Nullable SqlLiteral functionQualifier, SqlParserPos pos, @Nullable SqlNode... operands) { - pos = pos.plusAll(Arrays.asList(operands)); + pos = pos.plusAll(operands); operands = Arrays.copyOf(operands, operands.length + 1); operands[operands.length - 1] = SqlLiteral.createBoolean(caseSensitive, SqlParserPos.ZERO); return new SqlBasicCall(this, operands, pos, false, functionQualifier); diff --git a/core/src/main/java/org/apache/calcite/sql/parser/Span.java b/core/src/main/java/org/apache/calcite/sql/parser/Span.java index 07d5a125c7d3..0753044cb0b4 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/Span.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/Span.java @@ -130,14 +130,7 @@ public Span add(SqlAbstractParserImpl parser) { * Does not assume that the positions are sorted. * Throws if the list is empty. */ public SqlParserPos pos() { - switch (posList.size()) { - case 0: - throw new AssertionError(); - case 1: - return posList.get(0); - default: - return SqlParserPos.sum(posList); - } + return SqlParserPos.sum(posList); } /** Adds the position of the last token emitted by a parser to the list, diff --git a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java index e6b606ac2791..00f57aef61b4 100644 --- a/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java +++ b/core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java @@ -17,21 +17,16 @@ package org.apache.calcite.sql.parser; import org.apache.calcite.sql.SqlNode; -import org.apache.calcite.util.Util; import com.google.common.collect.Lists; import org.checkerframework.checker.nullness.qual.Nullable; -import org.checkerframework.checker.nullness.qual.PolyNull; import java.io.Serializable; -import java.util.AbstractList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; -import static org.apache.calcite.linq4j.Nullness.castNonNull; import static org.apache.calcite.util.Static.RESOURCE; /** @@ -164,19 +159,27 @@ public SqlParserPos plus(SqlParserPos pos) { * position that spans from the first point in the first to the last point * in the other. */ - public SqlParserPos plusAll(SqlNode[] nodes) { - return plusAll(Arrays.asList(nodes)); + public SqlParserPos plusAll(@Nullable SqlNode[] nodes) { + final PosBuilder b = new PosBuilder(this); + for (SqlNode node : nodes) { + if (node != null) { + b.add(node.getParserPosition()); + } + } + return b.build(this); } /** * Combines this parser position with a list of positions. */ - public SqlParserPos plusAll(Collection nodeList) { - int line = getLineNum(); - int column = getColumnNum(); - int endLine = getEndLineNum(); - int endColumn = getEndColumnNum(); - return sum(toPos(nodeList), line, column, endLine, endColumn); + public SqlParserPos plusAll(Collection nodes) { + final PosBuilder b = new PosBuilder(this); + for (SqlNode node : nodes) { + if (node != null) { + b.add(node.getParserPosition()); + } + } + return b.build(this); } /** @@ -184,24 +187,18 @@ public SqlParserPos plusAll(Collection nodeList) { * which spans from the beginning of the first to the end of the last. */ public static SqlParserPos sum(final SqlNode[] nodes) { - return sum(toPos(nodes)); - } - - private static List toPos(final SqlNode[] nodes) { - return new AbstractList() { - @Override public SqlParserPos get(int index) { - return nodes[index].getParserPosition(); - } - @Override public int size() { - return nodes.length; - } - }; - } - - private static Iterable<@PolyNull SqlParserPos> toPos( - Iterable nodes) { - return Util.transform(nodes, - node -> node == null ? castNonNull(null) : node.getParserPosition()); + if (nodes.length == 0) { + throw new AssertionError(); + } + final SqlParserPos pos0 = nodes[0].getParserPosition(); + if (nodes.length == 1) { + return pos0; + } + final PosBuilder b = new PosBuilder(pos0); + for (int i = 1; i < nodes.length; i++) { + b.add(nodes[i].getParserPosition()); + } + return b.build(pos0); } /** @@ -209,85 +206,40 @@ private static List toPos(final SqlNode[] nodes) { * which spans from the beginning of the first to the end of the last. */ public static SqlParserPos sum(final List nodes) { - return sum(Util.transform(nodes, SqlNode::getParserPosition)); + if (nodes.size() == 0) { + throw new AssertionError(); + } + SqlParserPos pos0 = nodes.get(0).getParserPosition(); + if (nodes.size() == 1) { + return pos0; + } + final PosBuilder b = new PosBuilder(pos0); + for (int i = 1; i < nodes.size(); i++) { + b.add(nodes.get(i).getParserPosition()); + } + return b.build(pos0); } - /** - * Combines an iterable of parser positions to create a position which spans - * from the beginning of the first to the end of the last. - */ + /** Returns a position spanning the earliest position to the latest. + * Does not assume that the positions are sorted. + * Throws if the list is empty. */ public static SqlParserPos sum(Iterable poses) { final List list = poses instanceof List ? (List) poses : Lists.newArrayList(poses); - return sum_(list); - } - - /** - * Combines a list of parser positions to create a position which spans - * from the beginning of the first to the end of the last. - */ - private static SqlParserPos sum_(final List positions) { - switch (positions.size()) { - case 0: + if (list.size() == 0) { throw new AssertionError(); - case 1: - return positions.get(0); - default: - final List poses = new AbstractList() { - @Override public SqlParserPos get(int index) { - return positions.get(index + 1); - } - @Override public int size() { - return positions.size() - 1; - } - }; - final SqlParserPos p = positions.get(0); - return sum(poses, p.lineNumber, p.columnNumber, p.endLineNumber, - p.endColumnNumber); } - } - - /** - * Computes the parser position which is the sum of an array of parser - * positions and of a parser position represented by (line, column, endLine, - * endColumn). - * - * @param poses Array of parser positions - * @param line Start line - * @param column Start column - * @param endLine End line - * @param endColumn End column - * @return Sum of parser positions - */ - private static SqlParserPos sum( - Iterable poses, - int line, - int column, - int endLine, - int endColumn) { - int testLine; - int testColumn; - for (SqlParserPos pos : poses) { - if (pos == null || pos.equals(SqlParserPos.ZERO)) { - continue; - } - testLine = pos.getLineNum(); - testColumn = pos.getColumnNum(); - if (testLine < line || testLine == line && testColumn < column) { - line = testLine; - column = testColumn; - } - - testLine = pos.getEndLineNum(); - testColumn = pos.getEndColumnNum(); - if (testLine > endLine || testLine == endLine && testColumn > endColumn) { - endLine = testLine; - endColumn = testColumn; - } + final SqlParserPos pos0 = list.get(0); + if (list.size() == 1) { + return pos0; + } + final PosBuilder b = new PosBuilder(pos0); + for (int i = 1; i < list.size(); i++) { + b.add(list.get(i)); } - return new SqlParserPos(line, column, endLine, endColumn); + return b.build(pos0); } public boolean overlaps(SqlParserPos pos) { @@ -324,4 +276,55 @@ private static class QuotedParserPos extends SqlParserPos { return true; } } + + /** Builds a parser position. */ + private static class PosBuilder { + private int line; + private int column; + private int endLine; + private int endColumn; + + PosBuilder(SqlParserPos p) { + this(p.lineNumber, p.columnNumber, p.endLineNumber, p.endColumnNumber); + } + + PosBuilder(int line, int column, int endLine, int endColumn) { + this.line = line; + this.column = column; + this.endLine = endLine; + this.endColumn = endColumn; + } + + void add(SqlParserPos pos) { + if (pos.equals(SqlParserPos.ZERO)) { + return; + } + int testLine = pos.getLineNum(); + int testColumn = pos.getColumnNum(); + if (testLine < line || testLine == line && testColumn < column) { + line = testLine; + column = testColumn; + } + + testLine = pos.getEndLineNum(); + testColumn = pos.getEndColumnNum(); + if (testLine > endLine || testLine == endLine && testColumn > endColumn) { + endLine = testLine; + endColumn = testColumn; + } + } + + SqlParserPos build(SqlParserPos p) { + return p.lineNumber == line + && p.columnNumber == column + && p.endLineNumber == endLine + && p.endColumnNumber == endColumn + ? p + : build(); + } + + SqlParserPos build() { + return new SqlParserPos(line, column, endLine, endColumn); + } + } }