Skip to content

Commit

Permalink
Refactor SqlParserPos
Browse files Browse the repository at this point in the history
Add private class PosBuilder to allow lists or arrays of positions to
be summed without creating intermediate collections. Nullness is also
more transparent.
  • Loading branch information
julianhyde authored and vlsi committed Nov 29, 2020
1 parent d71932e commit 73be222
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 111 deletions.
3 changes: 1 addition & 2 deletions core/src/main/java/org/apache/calcite/sql/SqlOperator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 1 addition & 8 deletions core/src/main/java/org/apache/calcite/sql/parser/Span.java
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
203 changes: 103 additions & 100 deletions core/src/main/java/org/apache/calcite/sql/parser/SqlParserPos.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -164,130 +159,87 @@ 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<? extends @Nullable SqlNode> 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<? extends @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 the parser positions of an array of nodes to create a position
* 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<SqlParserPos> toPos(final SqlNode[] nodes) {
return new AbstractList<SqlParserPos>() {
@Override public SqlParserPos get(int index) {
return nodes[index].getParserPosition();
}
@Override public int size() {
return nodes.length;
}
};
}

private static Iterable<@PolyNull SqlParserPos> toPos(
Iterable<? extends @PolyNull SqlNode> 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);
}

/**
* Combines the parser positions of a list of nodes to create a position
* which spans from the beginning of the first to the end of the last.
*/
public static SqlParserPos sum(final List<? extends SqlNode> 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<SqlParserPos> poses) {
final List<SqlParserPos> list =
poses instanceof List
? (List<SqlParserPos>) 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<SqlParserPos> positions) {
switch (positions.size()) {
case 0:
if (list.size() == 0) {
throw new AssertionError();
case 1:
return positions.get(0);
default:
final List<SqlParserPos> poses = new AbstractList<SqlParserPos>() {
@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<? extends @Nullable SqlParserPos> 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) {
Expand Down Expand Up @@ -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);
}
}
}

0 comments on commit 73be222

Please sign in to comment.