calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [2/3] calcite git commit: [CALCITE-1788] Simplify handling of position in the parser
Date Mon, 22 May 2017 02:46:16 GMT
http://git-wip-us.apache.org/repos/asf/calcite/blob/d6193040/core/src/main/codegen/templates/Parser.jj
----------------------------------------------------------------------
diff --git a/core/src/main/codegen/templates/Parser.jj b/core/src/main/codegen/templates/Parser.jj
index 83ed172..205e4fe 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -92,6 +92,7 @@ import org.apache.calcite.sql.fun.SqlCase;
 import org.apache.calcite.sql.fun.OracleSqlOperatorTable;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.fun.SqlTrimFunction;
+import org.apache.calcite.sql.parser.Span;
 import org.apache.calcite.sql.parser.SqlAbstractParserImpl;
 import org.apache.calcite.sql.parser.SqlParseException;
 import org.apache.calcite.sql.parser.SqlParser;
@@ -219,8 +220,7 @@ public class ${parser.class} extends SqlAbstractParserImpl
 
     private SqlNode extend(SqlNode table, SqlNodeList extendList) {
         return SqlStdOperatorTable.EXTEND.createCall(
-            table.getParserPosition().plus(extendList.getParserPosition()),
-            table, extendList);
+            Span.of(table, extendList).pos(), table, extendList);
     }
 }
 
@@ -311,13 +311,12 @@ SqlNode ExtendedBuiltinFunctionCall() :
 /*
 * Parse Floor/Ceil function parameters
 */
-SqlNode FloorCeilOptions(SqlParserPos pos, boolean floorFlag) :
+SqlNode FloorCeilOptions(Span s, boolean floorFlag) :
 {
     SqlNode node;
 }
 {
-    node = StandardFloorCeilOptions(pos, floorFlag)
-    {
+    node = StandardFloorCeilOptions(s, floorFlag) {
         return node;
     }
 }
@@ -377,7 +376,7 @@ JAVACODE List startList(Object o)
  * future changes to the grammar, making it very brittle.
  */
 
-JAVACODE SqlParserPos getPos()
+JAVACODE protected SqlParserPos getPos()
 {
     return new SqlParserPos(
         token.beginLine,
@@ -386,6 +385,12 @@ JAVACODE SqlParserPos getPos()
         token.endColumn);
 }
 
+/** Starts a span at the current position. */
+JAVACODE Span span()
+{
+    return Span.of(getPos());
+}
+
 JAVACODE void checkQueryExpression(ExprContext exprContext)
 {
     switch (exprContext) {
@@ -534,7 +539,7 @@ JAVACODE ParseException cleanupParseException(ParseException ex)
     if (ex.expectedTokenSequences == null) {
         return ex;
     }
-    int iIdentifier = java.util.Arrays.asList(ex.tokenImage).indexOf("<IDENTIFIER>");
+    int iIdentifier = Arrays.asList(ex.tokenImage).indexOf("<IDENTIFIER>");
 
     // Find all sequences in the error which contain identifier. For
     // example,
@@ -639,7 +644,6 @@ SqlNode OrderedQueryOrExpr(ExprContext exprContext) :
     SqlNodeList orderBy = null;
     SqlNode start = null;
     SqlNode count = null;
-    SqlParserPos pos = null;
 }
 {
     (
@@ -666,11 +670,10 @@ SqlNode OrderedQueryOrExpr(ExprContext exprContext) :
     ]
     {
         if (orderBy != null || start != null || count != null) {
-            pos = getPos();
             if (orderBy == null) {
                 orderBy = SqlNodeList.EMPTY;
             }
-            e = new SqlOrderBy(pos, e, orderBy, start, count);
+            e = new SqlOrderBy(getPos(), e, orderBy, start, count);
 
         }
         return e;
@@ -689,18 +692,11 @@ SqlNode LeafQuery(ExprContext exprContext) :
         // ensure a query is legal in this context
         checkQueryExpression(exprContext);
     }
-    e = SqlSelect()
-    {
-        return e;
-    }
-    | e = TableConstructor()
-    {
-        return e;
-    }
-    | e = ExplicitTable(getPos())
-    {
-        return e;
-    }
+    e = SqlSelect() { return e; }
+|
+    e = TableConstructor() { return e; }
+|
+    e = ExplicitTable(getPos()) { return e; }
 }
 
 /**
@@ -761,14 +757,14 @@ SqlNodeList ParenthesizedQueryOrCommaList(
     SqlNode e;
     List<SqlNode> list;
     ExprContext firstExprContext = exprContext;
-    SqlParserPos pos;
+    final Span s;
 }
 {
     <LPAREN>
     {
         // we've now seen left paren, so a query by itself should
         // be interpreted as a sub-query
-        pos = getPos();
+        s = span();
         switch (exprContext) {
         case ACCEPT_SUB_QUERY:
             firstExprContext = ExprContext.ACCEPT_NONCURSOR;
@@ -792,10 +788,10 @@ SqlNodeList ParenthesizedQueryOrCommaList(
         {
             list.add(e);
         }
-    ) *
+    )*
     <RPAREN>
     {
-        return new SqlNodeList(list, pos.plus(getPos()));
+        return new SqlNodeList(list, s.end(this));
     }
 }
 
@@ -873,8 +869,7 @@ void Arg0(List list, ExprContext exprContext) :
         if (e != null) {
             if (name != null) {
                 e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall(
-                    name.getParserPosition().plus(e.getParserPosition()),
-                    e, name);
+                    Span.of(name, e).pos(), e, name);
             }
             list.add(e);
         }
@@ -901,8 +896,7 @@ void Arg(List list, ExprContext exprContext) :
         if (e != null) {
             if (name != null) {
                 e = SqlStdOperatorTable.ARGUMENT_ASSIGNMENT.createCall(
-                    name.getParserPosition().plus(e.getParserPosition()),
-                    e, name);
+                    Span.of(name, e).pos(), e, name);
             }
             list.add(e);
         }
@@ -932,35 +926,35 @@ SqlNode SqlStmt() :
 }
 {
     (
-        stmt = SqlSetOption(null, null)
-        |
+        stmt = SqlSetOption(Span.of(), null)
+    |
         stmt = SqlAlter()
-        |
+    |
 <#if parser.createStatementParserMethods?size != 0>
         stmt = SqlCreate()
-        |
+    |
 </#if>
         stmt = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
-        |
+    |
         stmt = SqlExplain()
-        |
+    |
         stmt = SqlDescribe()
-        |
+    |
         stmt = SqlInsert()
-        |
+    |
         stmt = SqlDelete()
-        |
+    |
         stmt = SqlUpdate()
-        |
+    |
         stmt = SqlMerge()
-        |
+    |
         stmt = SqlProcedureCall()
 
-      <#-- Add methods to parse additional statements here -->
-      <#list parser.statementParserMethods as method>
-        |
+<#-- Add methods to parse additional statements here -->
+<#list parser.statementParserMethods as method>
+    |
         stmt = ${method}
-      </#list>
+</#list>
     )
     {
         return stmt;
@@ -992,18 +986,19 @@ SqlNode SqlStmtEof() :
 SqlSelect SqlSelect() :
 {
     final List<SqlLiteral> keywords = Lists.newArrayList();
+    final SqlNodeList keywordList;
     List<SqlNode> selectList;
     final SqlNode fromClause;
     final SqlNode where;
     final SqlNodeList groupBy;
     final SqlNode having;
     final SqlNodeList windowDecls;
-    SqlParserPos pos;
+    final Span s;
 }
 {
     <SELECT>
     {
-        pos = getPos();
+        s = span();
     }
     SqlSelectKeywords(keywords)
     (
@@ -1019,6 +1014,9 @@ SqlSelect SqlSelect() :
             keywords.add(SqlSelectKeyword.ALL.symbol(getPos()));
         }
     )?
+    {
+        keywordList = new SqlNodeList(keywords, s.addAll(keywords).pos());
+    }
     selectList = SelectList()
     (
         <FROM> fromClause = FromClause()
@@ -1036,11 +1034,8 @@ SqlSelect SqlSelect() :
         }
     )
     {
-        final SqlNode selectItem = (SqlNode)selectList.get(0);
-        final SqlParserPos selectListPos = selectItem.getParserPosition();
-        return new SqlSelect(pos.plus(getPos()),
-            new SqlNodeList(keywords, pos),
-            new SqlNodeList(selectList, selectListPos.plusAll(selectList)),
+        return new SqlSelect(s.end(this), keywordList,
+            new SqlNodeList(selectList, Span.of(selectList).pos()),
             fromClause, where, groupBy, having, windowDecls, null, null, null);
     }
 }
@@ -1061,7 +1056,6 @@ SqlNode SqlExplain() :
     SqlNode stmt;
     SqlExplainLevel detailLevel = SqlExplainLevel.EXPPLAN_ATTRIBUTES;
     SqlExplain.Depth depth;
-    SqlParserPos pos;
     final SqlExplainFormat format;
 }
 {
@@ -1076,8 +1070,7 @@ SqlNode SqlExplain() :
         { format = SqlExplainFormat.TEXT; }
     )
     <FOR> stmt = SqlQueryOrDml() {
-        pos = getPos();
-        return new SqlExplain(pos,
+        return new SqlExplain(getPos(),
             stmt,
             detailLevel.symbol(SqlParserPos.ZERO),
             depth.symbol(SqlParserPos.ZERO),
@@ -1168,19 +1161,21 @@ SqlExplainLevel ExplainDetailLevel() :
  */
 SqlNode SqlDescribe() :
 {
-   final SqlParserPos pos;
+   final Span s;
    final SqlIdentifier table;
    final SqlIdentifier column;
+   final SqlIdentifier id;
    final SqlNode stmt;
 }
 {
-    <DESCRIBE> { pos = getPos(); }
+    <DESCRIBE> { s = span(); }
     (
-        (<DATABASE> | <CATALOG> | <SCHEMA>) {
+        (<DATABASE> | <CATALOG> | <SCHEMA>)
+        id = CompoundIdentifier() {
             // DESCRIBE DATABASE and DESCRIBE CATALOG currently do the same as
             // DESCRIBE SCHEMA but should be different. See
             //   [CALCITE-1221] Implement DESCRIBE DATABASE, CATALOG, STATEMENT
-            return new SqlDescribeSchema(pos, CompoundIdentifier());
+            return new SqlDescribeSchema(s.end(id), id);
         }
     |
         // Use syntactic lookahead to determine whether a table name is coming.
@@ -1194,7 +1189,8 @@ SqlNode SqlDescribe() :
         |
             E() { column = null; }
         ) {
-            return new SqlDescribeTable(pos, table, column);
+            return new SqlDescribeTable(s.add(table).addIf(column).pos(),
+                table, column);
         }
     |
         (<STATEMENT>)?
@@ -1204,7 +1200,7 @@ SqlNode SqlDescribe() :
             final SqlExplainLevel detailLevel = SqlExplainLevel.EXPPLAN_ATTRIBUTES;
             final SqlExplain.Depth depth = SqlExplain.Depth.PHYSICAL;
             final SqlExplainFormat format = SqlExplainFormat.TEXT;
-            return new SqlExplain(pos,
+            return new SqlExplain(s.end(stmt),
                 stmt,
                 detailLevel.symbol(SqlParserPos.ZERO),
                 depth.symbol(SqlParserPos.ZERO),
@@ -1219,20 +1215,19 @@ SqlNode SqlDescribe() :
  */
 SqlNode SqlProcedureCall() :
 {
-    SqlParserPos callPos;
+    final Span s;
     SqlNode routineCall;
 }
 {
-    <CALL>
-    {
-        callPos = getPos();
+    <CALL> {
+        s = span();
     }
     routineCall = NamedRoutineCall(
         SqlFunctionCategory.USER_DEFINED_PROCEDURE,
         ExprContext.ACCEPT_SUB_QUERY)
     {
         return SqlStdOperatorTable.PROCEDURE_CALL.createCall(
-            callPos, routineCall);
+            s.end(routineCall), routineCall);
     }
 }
 
@@ -1242,11 +1237,11 @@ SqlNode NamedRoutineCall(
 {
     SqlIdentifier name;
     final List<SqlNode> list = Lists.newArrayList();
-    final SqlParserPos pos;
+    final Span s;
 }
 {
     name = CompoundIdentifier() {
-        pos = getPos();
+        s = span();
     }
     <LPAREN>
     [
@@ -1261,9 +1256,7 @@ SqlNode NamedRoutineCall(
     ]
     <RPAREN>
     {
-        SqlNode function = createCall(
-            name, pos.plus(getPos()), routineType, null, SqlParserUtil.toNodeArray(list));
-        return function;
+        return createCall(name, s.end(this), routineType, null, list);
     }
 }
 
@@ -1273,11 +1266,12 @@ SqlNode NamedRoutineCall(
 SqlNode SqlInsert() :
 {
     final List<SqlLiteral> keywords = Lists.newArrayList();
+    final SqlNodeList keywordList;
     SqlNode table;
     SqlNodeList extendList = null;
     SqlNode source;
     SqlNodeList columnList = null;
-    SqlParserPos pos;
+    final Span s;
 }
 {
     (
@@ -1285,7 +1279,10 @@ SqlNode SqlInsert() :
     |
         <UPSERT> { keywords.add(SqlInsertKeyword.UPSERT.symbol(getPos())); }
     )
-    SqlInsertKeywords(keywords)
+    { s = span(); }
+    SqlInsertKeywords(keywords) {
+        keywordList = new SqlNodeList(keywords, s.addAll(keywords).pos());
+    }
     <INTO> table = CompoundIdentifier()
     [
         LOOKAHEAD(3)
@@ -1294,16 +1291,12 @@ SqlNode SqlInsert() :
             table = extend(table, extendList);
         }
     ]
-    {
-        pos = getPos();
-    }
     [
         LOOKAHEAD(2)
         columnList = ParenthesizedCompoundIdentifierList()
     ]
-    source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY)
-    {
-        return new SqlInsert(pos, new SqlNodeList(keywords, pos), table, source,
+    source = OrderedQueryOrExpr(ExprContext.ACCEPT_QUERY) {
+        return new SqlInsert(s.end(source), keywordList, table, source,
             columnList);
     }
 }
@@ -1324,18 +1317,14 @@ SqlNode SqlDelete() :
     SqlNode table;
     SqlNodeList extendList = null;
     SqlIdentifier alias = null;
-    SqlNode condition;
-    SqlParserPos pos;
+    final SqlNode condition;
+    final Span s;
 }
 {
-    <DELETE>
-    {
-        pos = getPos();
+    <DELETE> {
+        s = span();
     }
     <FROM> table = CompoundIdentifier()
-    {
-
-    }
     [
         [ <EXTEND> ]
         extendList = ExtendList() {
@@ -1345,7 +1334,8 @@ SqlNode SqlDelete() :
     [ [ <AS> ] alias = SimpleIdentifier() ]
     condition = WhereOpt()
     {
-        return new SqlDelete(pos, table, condition, null, alias);
+        return new SqlDelete(s.add(table).addIf(extendList).addIf(alias)
+            .addIf(condition).pos(), table, condition, null, alias);
     }
 }
 
@@ -1362,14 +1352,13 @@ SqlNode SqlUpdate() :
     SqlNodeList targetColumnList;
     SqlIdentifier id;
     SqlNode exp;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <UPDATE> table = CompoundIdentifier()
-    {
-        pos = getPos();
-        targetColumnList = new SqlNodeList(pos);
-        sourceExpressionList = new SqlNodeList(pos);
+    <UPDATE> { s = span(); }
+    table = CompoundIdentifier() {
+        targetColumnList = new SqlNodeList(s.pos());
+        sourceExpressionList = new SqlNodeList(s.pos());
     }
     [
         [ <EXTEND> ]
@@ -1378,12 +1367,10 @@ SqlNode SqlUpdate() :
         }
     ]
     [ [ <AS> ] alias = SimpleIdentifier() ]
-    <SET> id = SimpleIdentifier()
-    {
+    <SET> id = SimpleIdentifier() {
         targetColumnList.add(id);
     }
-    <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
-    {
+    <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY) {
         // TODO:  support DEFAULT also
         sourceExpressionList.add(exp);
     }
@@ -1397,11 +1384,12 @@ SqlNode SqlUpdate() :
         {
             sourceExpressionList.add(exp);
         }
-    ) *
+    )*
     condition = WhereOpt()
     {
-        return new SqlUpdate(pos, table, targetColumnList, sourceExpressionList,
-            condition, null, alias);
+        return new SqlUpdate(s.addAll(targetColumnList)
+            .addAll(sourceExpressionList).addIf(condition).pos(), table,
+            targetColumnList, sourceExpressionList, condition, null, alias);
     }
 }
 
@@ -1417,13 +1405,10 @@ SqlNode SqlMerge() :
     SqlNode condition;
     SqlUpdate updateCall = null;
     SqlInsert insertCall = null;
-    SqlParserPos mergePos;
+    final Span s;
 }
 {
-    <MERGE> <INTO> table = CompoundIdentifier()
-    {
-        mergePos = getPos();
-    }
+    <MERGE> { s = span(); } <INTO> table = CompoundIdentifier()
     [
         [ <EXTEND> ]
         extendList = ExtendList() {
@@ -1431,83 +1416,74 @@ SqlNode SqlMerge() :
         }
     ]
     [ [ <AS> ] alias = SimpleIdentifier() ]
-
     <USING> sourceTableRef = TableRef()
-
     <ON> condition = Expression(ExprContext.ACCEPT_SUB_QUERY)
-
     (
-    LOOKAHEAD(2)
-    updateCall = WhenMatchedClause(table, alias)
-    [ insertCall = WhenNotMatchedClause(table) ]
+        LOOKAHEAD(2)
+        updateCall = WhenMatchedClause(table, alias)
+        [ insertCall = WhenNotMatchedClause(table) ]
     |
-    insertCall = WhenNotMatchedClause(table)
+        insertCall = WhenNotMatchedClause(table)
     )
     {
-        return new SqlMerge(mergePos, table, condition, sourceTableRef,
-            updateCall, insertCall, null, alias);
+        return new SqlMerge(s.addIf(updateCall).addIf(insertCall).pos(), table,
+            condition, sourceTableRef, updateCall, insertCall, null, alias);
     }
 }
 
 SqlUpdate WhenMatchedClause(SqlNode table, SqlIdentifier alias) :
 {
     SqlIdentifier id;
-    SqlParserPos pos;
-    SqlNodeList updateColumnList;
+    final Span s;
+    final SqlNodeList updateColumnList = new SqlNodeList(SqlParserPos.ZERO);
     SqlNode exp;
-    SqlNodeList updateExprList;
+    final SqlNodeList updateExprList = new SqlNodeList(SqlParserPos.ZERO);
 }
 {
-    <WHEN> <MATCHED> <THEN>
-    <UPDATE> <SET> id = SimpleIdentifier()
-    {
-        pos = getPos();
-        updateColumnList = new SqlNodeList(pos);
-        updateExprList = new SqlNodeList(pos);
+    <WHEN> { s = span(); } <MATCHED> <THEN>
+    <UPDATE> <SET> id = SimpleIdentifier() {
         updateColumnList.add(id);
     }
-    <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
-    {
+    <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY) {
         updateExprList.add(exp);
     }
     (
         <COMMA>
-        id = SimpleIdentifier()
-        {
+        id = SimpleIdentifier() {
             updateColumnList.add(id);
         }
-        <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY)
-        {
+        <EQ> exp = Expression(ExprContext.ACCEPT_SUB_QUERY) {
             updateExprList.add(exp);
         }
-    ) *
+    )*
     {
-        return new SqlUpdate(pos, table, updateColumnList, updateExprList, null,
-            null, alias);
+        return new SqlUpdate(s.addAll(updateExprList).pos(), table,
+            updateColumnList, updateExprList, null, null, alias);
     }
 }
 
 SqlInsert WhenNotMatchedClause(SqlNode table) :
 {
-    SqlParserPos pos, insertPos;
-    List<SqlLiteral> keywords = Lists.newArrayList();
+    final Span insertSpan, valuesSpan;
+    final List<SqlLiteral> keywords = Lists.newArrayList();
+    final SqlNodeList keywordList;
     SqlNodeList insertColumnList = null;
     SqlNode rowConstructor;
     SqlNode insertValues;
 }
 {
-    <WHEN> <NOT> <MATCHED> <THEN>
-    <INSERT>
-    {
-        insertPos = getPos();
+    <WHEN> <NOT> <MATCHED> <THEN> <INSERT> {
+        insertSpan = span();
+    }
+    SqlInsertKeywords(keywords) {
+        keywordList = new SqlNodeList(keywords, insertSpan.end(this));
     }
-    SqlInsertKeywords(keywords)
     [
         LOOKAHEAD(2)
         insertColumnList = ParenthesizedSimpleIdentifierList()
     ]
     [ <LPAREN> ]
-    <VALUES> { pos = getPos(); }
+    <VALUES> { valuesSpan = span(); }
     rowConstructor = RowConstructor()
     [ <RPAREN> ]
     {
@@ -1515,9 +1491,8 @@ SqlInsert WhenNotMatchedClause(SqlNode table) :
         // around the VALUES clause as a hack for unparse, but this is
         // actually invalid SQL; should fix unparse
         insertValues = SqlStdOperatorTable.VALUES.createCall(
-            pos.plus(rowConstructor.getParserPosition()),
-            rowConstructor);
-        return new SqlInsert(insertPos, new SqlNodeList(keywords, insertPos),
+            valuesSpan.end(this), rowConstructor);
+        return new SqlInsert(insertSpan.end(this), keywordList,
             table, insertValues, insertColumnList);
     }
 }
@@ -1527,12 +1502,18 @@ SqlInsert WhenNotMatchedClause(SqlNode table) :
  */
 List<SqlNode> SelectList() :
 {
-    List<SqlNode> list = new ArrayList<SqlNode>();
+    final List<SqlNode> list = new ArrayList<SqlNode>();
     SqlNode item;
 }
 {
-    item = SelectItem() {list.add(item);}
-    ( <COMMA> item = SelectItem() {list.add(item);} ) *
+    item = SelectItem() {
+        list.add(item);
+    }
+    (
+        <COMMA> item = SelectItem() {
+            list.add(item);
+        }
+    )*
     {
         return list;
     }
@@ -1545,16 +1526,13 @@ SqlNode SelectItem() :
 {
     SqlNode e;
     SqlIdentifier id;
-    SqlParserPos pos;
 }
 {
     e = SelectExpression()
     [
         [ <AS> ]
-        id = SimpleIdentifier()
-        {
-            pos = e.getParserPosition().plus(getPos());
-            e = SqlStdOperatorTable.AS.createCall(pos, e, id);
+        id = SimpleIdentifier() {
+            e = SqlStdOperatorTable.AS.createCall(span().end(e), e, id);
         }
     ]
     {
@@ -1570,13 +1548,11 @@ SqlNode SelectExpression() :
     SqlNode e;
 }
 {
-    <STAR>
-    {
+    <STAR> {
         return SqlIdentifier.star(getPos());
     }
-    |
-    e = Expression(ExprContext.ACCEPT_SUB_QUERY)
-    {
+|
+    e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
         return e;
     }
 }
@@ -1585,11 +1561,9 @@ SqlLiteral Natural() :
 {
 }
 {
-    (
-        <NATURAL> { return SqlLiteral.createBoolean(true, getPos()); }
-    |
-        { return SqlLiteral.createBoolean(false, getPos()); }
-    )
+    <NATURAL> { return SqlLiteral.createBoolean(true, getPos()); }
+|
+    { return SqlLiteral.createBoolean(false, getPos()); }
 }
 
 SqlLiteral JoinType() :
@@ -1619,37 +1593,34 @@ SqlLiteral JoinType() :
 SqlNode JoinTable(SqlNode e) :
 {
     SqlNode e2, condition;
-    SqlLiteral natural, joinType;
+    final SqlLiteral natural, joinType, on, using;
     SqlNodeList list;
-    SqlParserPos pos;
 }
 {
     natural = Natural()
     joinType = JoinType()
     e2 = TableRef()
     (
-        <ON> { pos = getPos(); }
+        <ON> { on = JoinConditionType.ON.symbol(getPos()); }
         condition = Expression(ExprContext.ACCEPT_SUB_QUERY) {
-            SqlParserPos onPos = pos.plus(getPos());
             return new SqlJoin(joinType.getParserPosition(),
                 e,
                 natural,
                 joinType,
                 e2,
-                JoinConditionType.ON.symbol(onPos),
+                on,
                 condition);
         }
     |
-        <USING> { pos = getPos(); }
+        <USING> { using = JoinConditionType.USING.symbol(getPos()); }
         list = ParenthesizedSimpleIdentifierList() {
-            SqlParserPos usingPos = pos.plus(getPos());
             return new SqlJoin(joinType.getParserPosition(),
                 e,
                 natural,
                 joinType,
                 e2,
-                JoinConditionType.USING.symbol(usingPos),
-                new SqlNodeList(list.getList(), usingPos));
+                using,
+                new SqlNodeList(list.getList(), Span.of(using).end(this)));
         }
     |
         {
@@ -1682,7 +1653,7 @@ SqlNode JoinTable(SqlNode e) :
 SqlNode FromClause() :
 {
     SqlNode e, e2, condition;
-    SqlLiteral natural, joinType;
+    SqlLiteral natural, joinType, joinConditionType;
     SqlNodeList list;
     SqlParserPos pos;
 }
@@ -1697,30 +1668,32 @@ SqlNode FromClause() :
         joinType = JoinType()
         e2 = TableRef()
         (
-            <ON> { pos = getPos(); }
+            <ON> {
+                joinConditionType = JoinConditionType.ON.symbol(getPos());
+            }
             condition = Expression(ExprContext.ACCEPT_SUB_QUERY) {
-                SqlParserPos onPos = pos.plus(getPos());
                 e = new SqlJoin(joinType.getParserPosition(),
                     e,
                     natural,
                     joinType,
                     e2,
-                    JoinConditionType.ON.symbol(onPos),
+                    joinConditionType,
                     condition);
             }
-            |
-            <USING> { pos = getPos(); }
+        |
+            <USING> {
+                joinConditionType = JoinConditionType.USING.symbol(getPos());
+            }
             list = ParenthesizedSimpleIdentifierList() {
-                SqlParserPos usingPos = pos.plus(getPos());
                 e = new SqlJoin(joinType.getParserPosition(),
                     e,
                     natural,
                     joinType,
                     e2,
-                    JoinConditionType.USING.symbol(usingPos),
-                    new SqlNodeList(list.getList(), usingPos));
+                    joinConditionType,
+                    new SqlNodeList(list.getList(), Span.of(joinConditionType).end(this)));
             }
-            |
+        |
             {
                 e = new SqlJoin(joinType.getParserPosition(),
                     e,
@@ -1731,62 +1704,56 @@ SqlNode FromClause() :
                     null);
             }
         )
-        |
+    |
         // NOTE jvs 6-Feb-2004:  See comments at top of file for why
         // hint is necessary here.  I had to use this special semantic
         // lookahead form to get JavaCC to shut up, which makes
         // me even more uneasy.
         //LOOKAHEAD({true})
-        <COMMA> { pos = getPos(); }
+        <COMMA> { joinType = JoinType.COMMA.symbol(getPos()); }
         e2 = TableRef() {
-            e = new SqlJoin(pos,
+            e = new SqlJoin(joinType.getParserPosition(),
                 e,
-                SqlLiteral.createBoolean(false, pos),
-                JoinType.COMMA.symbol(SqlParserPos.ZERO),
+                SqlLiteral.createBoolean(false, joinType.getParserPosition()),
+                joinType,
                 e2,
                 JoinConditionType.NONE.symbol(SqlParserPos.ZERO),
                 null);
         }
-        |
-        <CROSS> { pos = getPos(); } <APPLY>
+    |
+        <CROSS> { joinType = JoinType.CROSS.symbol(getPos()); } <APPLY>
         e2 = TableRef2(true) {
             if (!this.conformance.isApplyAllowed()) {
                 throw new ParseException(RESOURCE.applyNotAllowed().str());
             }
-            e = new SqlJoin(pos,
+            e = new SqlJoin(joinType.getParserPosition(),
                 e,
-                SqlLiteral.createBoolean(false, pos),
-                JoinType.CROSS.symbol(SqlParserPos.ZERO),
+                SqlLiteral.createBoolean(false, joinType.getParserPosition()),
+                joinType,
                 e2,
                 JoinConditionType.NONE.symbol(SqlParserPos.ZERO),
                 null);
         }
-        |
-        <OUTER> { pos = getPos(); } <APPLY>
+    |
+        <OUTER> { joinType = JoinType.LEFT.symbol(getPos()); } <APPLY>
         e2 = TableRef2(true) {
             if (!this.conformance.isApplyAllowed()) {
                 throw new ParseException(RESOURCE.applyNotAllowed().str());
             }
-            e = new SqlJoin(pos,
+            e = new SqlJoin(joinType.getParserPosition(),
                 e,
-                SqlLiteral.createBoolean(false, pos),
-                JoinType.LEFT.symbol(SqlParserPos.ZERO),
+                SqlLiteral.createBoolean(false, joinType.getParserPosition()),
+                joinType,
                 e2,
                 JoinConditionType.ON.symbol(SqlParserPos.ZERO),
-                SqlLiteral.createBoolean(true, pos));
+                SqlLiteral.createBoolean(true, joinType.getParserPosition()));
         }
-    ) *
+    )*
     {
         return e;
     }
 }
 
-// TODO jvs 15-Nov-2003: SQL standard allows column aliases on table
-// references, e.g. DEPTS AS D1(DEPTNO1,DNAME1); I guess this is syntactic
-// sugar to make it easier for query writers to conform to the column name
-// uniqueness rules without requiring them to write a nested SELECT, but it
-// seems pretty useless for non-trivial tables, since you have to supply names
-// for ALL columns at once.
 /**
  * Parses a table reference in a FROM clause, not lateral unless LATERAL
  * is explicitly specified.
@@ -1808,7 +1775,8 @@ SqlNode TableRef2(boolean lateral) :
     SqlNode over;
     SqlNodeList extendList = null;
     String alias;
-    SqlParserPos pos;
+    final SqlIdentifier id;
+    final Span s, s2;
     SqlNodeList args;
     SqlNode sample;
     boolean isBernoulli;
@@ -1831,9 +1799,8 @@ SqlNode TableRef2(boolean lateral) :
         over = TableOverOpt()
         {
             if (over != null) {
-                pos = getPos();
                 tableRef = SqlStdOperatorTable.OVER.createCall(
-                    pos, tableRef, over);
+                    getPos(), tableRef, over);
             }
         }
         [
@@ -1850,9 +1817,8 @@ SqlNode TableRef2(boolean lateral) :
         over = TableOverOpt()
         {
             if (over != null) {
-                pos = getPos();
                 tableRef = SqlStdOperatorTable.OVER.createCall(
-                    pos, tableRef, over);
+                    getPos(), tableRef, over);
             }
             if (lateral) {
                 tableRef = SqlStdOperatorTable.LATERAL.createCall(
@@ -1868,7 +1834,7 @@ SqlNode TableRef2(boolean lateral) :
             }
         )
     |
-        <UNNEST> { pos = getPos(); }
+        <UNNEST> { s = span(); }
         args = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_SUB_QUERY)
         [
             <WITH> <ORDINALITY> {
@@ -1876,51 +1842,54 @@ SqlNode TableRef2(boolean lateral) :
             }
         ]
         {
-            tableRef = unnestOp.createCall(pos.plus(getPos()), args.toArray());
+            tableRef = unnestOp.createCall(s.end(this), args.toArray());
         }
     |
         [ <LATERAL> { lateral = true; } ]
-        <TABLE> { pos = getPos(); } <LPAREN>
-        tableRef = TableFunctionCall(pos)
+        <TABLE> { s = span(); } <LPAREN>
+        tableRef = TableFunctionCall(s.pos())
         <RPAREN>
         {
             if (lateral) {
                 tableRef = SqlStdOperatorTable.LATERAL.createCall(
-                    getPos(), tableRef);
+                    s.end(this), tableRef);
             }
         }
     |
         tableRef = ExtendedTableRef()
     )
     [
-        [ <AS> ] alias = Identifier()
+        [ <AS> ] alias = Identifier() {
+            id = new SqlIdentifier(alias, getPos());
+        }
         [ columnAliasList = ParenthesizedSimpleIdentifierList() ]
         {
-            pos = getPos();
             if (columnAliasList == null) {
                 tableRef = SqlStdOperatorTable.AS.createCall(
-                    pos, tableRef, new SqlIdentifier(alias, pos));
+                    Span.of(tableRef).end(this), tableRef, id);
             } else {
                 List<SqlNode> idList = new ArrayList<SqlNode>();
                 idList.add(tableRef);
-                idList.add(new SqlIdentifier(alias, pos));
+                idList.add(id);
                 idList.addAll(columnAliasList.getList());
-                tableRef = SqlStdOperatorTable.AS.createCall(pos, idList);
+                tableRef = SqlStdOperatorTable.AS.createCall(
+                    Span.of(tableRef).end(this), idList);
             }
         }
     ]
     [
-        <TABLESAMPLE> { pos = getPos(); }
+        <TABLESAMPLE> { s2 = span(); }
         (
             <SUBSTITUTE> <LPAREN> sample = StringLiteral() <RPAREN>
             {
                 String sampleName =
                     ((NlsString) SqlLiteral.value(sample)).getValue();
                 SqlSampleSpec sampleSpec = SqlSampleSpec.createNamed(sampleName);
-                SqlLiteral sampleLiteral = SqlLiteral.createSample(sampleSpec, pos);
+                final SqlLiteral sampleLiteral =
+                    SqlLiteral.createSample(sampleSpec, s2.end(this));
                 tableRef = SqlStdOperatorTable.TABLESAMPLE.createCall(
-                    pos.plus(getPos()), tableRef, sampleLiteral);
-             }
+                    s2.add(tableRef).end(this), tableRef, sampleLiteral);
+            }
         |
             (
                 <BERNOULLI>
@@ -1964,9 +1933,9 @@ SqlNode TableRef2(boolean lateral) :
                         : SqlSampleSpec.createTableSample(isBernoulli, fRate);
 
                     SqlLiteral tableSampleLiteral =
-                        SqlLiteral.createSample(tableSampleSpec, pos);
+                        SqlLiteral.createSample(tableSampleSpec, s2.end(this));
                     tableRef = SqlStdOperatorTable.TABLESAMPLE.createCall(
-                        pos.plus(getPos()), tableRef, tableSampleLiteral);
+                        s2.end(this), tableRef, tableSampleLiteral);
                 }
             }
         )
@@ -1978,17 +1947,17 @@ SqlNode TableRef2(boolean lateral) :
 
 SqlNodeList ExtendList() :
 {
-    SqlParserPos pos;
+    final Span s;
     List<SqlNode> list = Lists.newArrayList();
 }
 {
-    <LPAREN> { pos = getPos(); }
+    <LPAREN> { s = span(); }
     ColumnType(list)
     (
         <COMMA> ColumnType(list)
     )*
     <RPAREN> {
-        return new SqlNodeList(list, pos.plus(getPos()));
+        return new SqlNodeList(list, s.end(this));
     }
 }
 
@@ -2024,8 +1993,6 @@ SqlNode TableFunctionCall(SqlParserPos pos) :
             funcType = SqlFunctionCategory.USER_DEFINED_TABLE_SPECIFIC_FUNCTION;
         }
     ]
-    {
-    }
     call = NamedRoutineCall(funcType, ExprContext.ACCEPT_CURSOR)
     {
         return SqlStdOperatorTable.COLLECTION_TABLE.createCall(pos, call);
@@ -2069,24 +2036,21 @@ SqlNode ExplicitTable(SqlParserPos pos) :
 SqlNode TableConstructor() :
 {
     SqlNodeList rowConstructorList;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <VALUES>
-    {
-        pos = getPos();
-    }
-    rowConstructorList = RowConstructorList(pos)
+    <VALUES> { s = span(); }
+    rowConstructorList = RowConstructorList(s)
     {
         return SqlStdOperatorTable.VALUES.createCall(
-            pos.plus(getPos()), rowConstructorList.toArray());
+            s.end(this), rowConstructorList.toArray());
     }
 }
 
 /**
  * Parses one or more rows in a VALUES expression.
  */
-SqlNodeList RowConstructorList(SqlParserPos pos) :
+SqlNodeList RowConstructorList(Span s) :
 {
     List<SqlNode> list = new ArrayList<SqlNode>();
     SqlNode rowConstructor;
@@ -2096,9 +2060,9 @@ SqlNodeList RowConstructorList(SqlParserPos pos) :
     (
         LOOKAHEAD(2)
         <COMMA> rowConstructor = RowConstructor() { list.add(rowConstructor); }
-    ) *
+    )*
     {
-        return new SqlNodeList(list, pos.plus(getPos()));
+        return new SqlNodeList(list, s.end(this));
     }
 }
 
@@ -2109,7 +2073,7 @@ SqlNode RowConstructor() :
 {
     SqlNodeList valueList;
     SqlNode value;
-    SqlParserPos pos;
+    final Span s;
 }
 {
     // hints are necessary here due to common LPAREN prefixes
@@ -2118,19 +2082,19 @@ SqlNode RowConstructor() :
         // for unparse, but this is actually invalid SQL; should
         // fix unparse
         LOOKAHEAD(3)
-        <LPAREN> { pos = getPos(); }
+        <LPAREN> { s = span(); }
         <ROW>
         valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
-        <RPAREN> { pos = pos.plus(getPos()); }
-        |
+        <RPAREN> { s.add(this); }
+    |
         LOOKAHEAD(3)
-        { pos = getPos(); }
-        [
-            <ROW>
-        ]
-        valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
-        { pos = pos.plus(getPos()); }
+        (
+            <ROW> { s = span(); }
         |
+            { s = Span.of(); }
+        )
+        valueList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
+    |
         value = Expression(ExprContext.ACCEPT_NONCURSOR)
         {
             // NOTE: A bare value here is standard SQL syntax, believe it or
@@ -2139,15 +2103,17 @@ SqlNode RowConstructor() :
             // single-row constructor.  This is also the reason for the
             // LOOKAHEAD in RowConstructorList().  It would be so much more
             // reasonable to require parentheses.  Sigh.
-            pos = value.getParserPosition();
-            valueList = new SqlNodeList(Collections.singletonList(value), pos);
+            s = Span.of(value);
+            valueList = new SqlNodeList(Collections.singletonList(value),
+                value.getParserPosition());
         }
     )
     {
         // REVIEW jvs 8-Feb-2004: Should we discriminate between scalar
         // sub-queries inside of ROW and row sub-queries?  The standard does,
         // but the distinction seems to be purely syntactic.
-        return SqlStdOperatorTable.ROW.createCall(pos, valueList.toArray());
+        return SqlStdOperatorTable.ROW.createCall(s.end(valueList),
+            valueList.toArray());
     }
 }
 
@@ -2175,13 +2141,12 @@ SqlNode WhereOpt() :
 SqlNodeList GroupByOpt() :
 {
     List<SqlNode> list = Lists.newArrayList();
-    SqlNode e;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <GROUP> { pos = getPos(); }
+    <GROUP> { s = span(); }
     <BY> list = GroupingElementList() {
-        return new SqlNodeList(list, pos.plusAll(list));
+        return new SqlNodeList(list, s.addAll(list).pos());
     }
 |
     {
@@ -2206,24 +2171,26 @@ List<SqlNode> GroupingElementList() :
 SqlNode GroupingElement() :
 {
     List<SqlNode> list;
-    SqlNodeList nlist;
-    SqlNode e;
-    SqlParserPos pos;
+    final SqlNodeList nodes;
+    final SqlNode e;
+    final Span s;
 }
 {
-    <GROUPING> { pos = getPos(); }
+    <GROUPING> { s = span(); }
     <SETS> <LPAREN> list = GroupingElementList() <RPAREN> {
-        return SqlStdOperatorTable.GROUPING_SETS.createCall(pos, list);
+        return SqlStdOperatorTable.GROUPING_SETS.createCall(s.end(this), list);
     }
-|   <ROLLUP> { pos = getPos(); }
-    <LPAREN> nlist = ExpressionCommaList(pos, ExprContext.ACCEPT_SUB_QUERY)
+|   <ROLLUP> { s = span(); }
+    <LPAREN> nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY)
     <RPAREN> {
-        return SqlStdOperatorTable.ROLLUP.createCall(nlist);
+        return SqlStdOperatorTable.ROLLUP.createCall(s.end(this),
+            nodes.getList());
     }
-|   <CUBE> { pos = getPos(); }
-    <LPAREN> nlist = ExpressionCommaList(pos, ExprContext.ACCEPT_SUB_QUERY)
+|   <CUBE> { s = span(); }
+    <LPAREN> nodes = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY)
     <RPAREN> {
-        return SqlStdOperatorTable.CUBE.createCall(nlist);
+        return SqlStdOperatorTable.CUBE.createCall(s.end(this),
+            nodes.getList());
     }
 |   LOOKAHEAD(3)
     <LPAREN> <RPAREN> {
@@ -2238,7 +2205,7 @@ SqlNode GroupingElement() :
  * Parses a list of expressions separated by commas.
  */
 SqlNodeList ExpressionCommaList(
-    SqlParserPos pos,
+    final Span s,
     ExprContext exprContext) :
 {
     List<SqlNode> list;
@@ -2247,10 +2214,6 @@ SqlNodeList ExpressionCommaList(
 {
     e = Expression(exprContext)
     {
-        if (pos == null) {
-            pos = getPos();
-        }
-        pos = pos.plus(getPos());
         list = startList(e);
     }
     (
@@ -2260,11 +2223,10 @@ SqlNodeList ExpressionCommaList(
         <COMMA> e = Expression(ExprContext.ACCEPT_SUB_QUERY)
         {
             list.add(e);
-            pos = pos.plus(getPos());
         }
-    ) *
+    )*
     {
-        return new SqlNodeList(list, pos);
+        return new SqlNodeList(list, s.addAll(list).pos());
     }
 }
 
@@ -2276,14 +2238,9 @@ SqlNode HavingOpt() :
     SqlNode e;
 }
 {
-    <HAVING> e = Expression(ExprContext.ACCEPT_SUB_QUERY)
-    {
-        return e;
-    }
-    |
-    {
-        return null;
-    }
+    <HAVING> e = Expression(ExprContext.ACCEPT_SUB_QUERY) { return e; }
+|
+    { return null; }
 }
 
 /**
@@ -2294,12 +2251,11 @@ SqlNodeList WindowOpt() :
     SqlIdentifier id;
     SqlWindow e;
     List<SqlNode> list;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <WINDOW> id = SimpleIdentifier() <AS> e = WindowSpecification()
-    {
-        pos = getPos();
+    <WINDOW> { s = span(); }
+    id = SimpleIdentifier() <AS> e = WindowSpecification() {
         e.setDeclName(id);
         list = startList(e);
     }
@@ -2307,16 +2263,15 @@ SqlNodeList WindowOpt() :
         // NOTE jhyde 22-Oct-2004:  See comments at top of file for why
         // hint is necessary here.
         LOOKAHEAD(2)
-        <COMMA> id = SimpleIdentifier() <AS> e = WindowSpecification()
-        {
+        <COMMA> id = SimpleIdentifier() <AS> e = WindowSpecification() {
             e.setDeclName(id);
             list.add(e);
         }
-    ) *
+    )*
     {
-        return new SqlNodeList(list, pos);
+        return new SqlNodeList(list, s.addAll(list).pos());
     }
-    |
+|
     {
         return null;
     }
@@ -2334,103 +2289,87 @@ SqlWindow WindowSpecification() :
     SqlLiteral isRows = SqlLiteral.createBoolean(false, SqlParserPos.ZERO);
     SqlNode lowerBound = null, upperBound = null;
     SqlParserPos startPos;
-    SqlParserPos endPos;
-    SqlParserPos pos;
+    final Span s, s1, s2;
     SqlLiteral allowPartial = null;
 }
 {
-    <LPAREN> { startPos = pos = getPos(); }
+    <LPAREN> { s = span(); }
     (
         id = SimpleIdentifier()
-        |
+    |
         { id = null; }
     )
     (
-        <PARTITION>
-        { pos = getPos(); }
+        <PARTITION> { s1 = span(); }
         <BY>
-        partitionList = ExpressionCommaList(pos, ExprContext.ACCEPT_NON_QUERY)
-        |
+        partitionList = ExpressionCommaList(s1, ExprContext.ACCEPT_NON_QUERY)
+    |
         { partitionList = SqlNodeList.EMPTY; }
     )
     (
         orderList = OrderBy(true)
-        |
+    |
         { orderList = SqlNodeList.EMPTY; }
     )
     [
         (
             <ROWS> { isRows = SqlLiteral.createBoolean(true, getPos()); }
-            |
+        |
             <RANGE> { isRows = SqlLiteral.createBoolean(false, getPos()); }
         )
         (
             <BETWEEN> lowerBound = WindowRange()
             <AND> upperBound = WindowRange()
-            |
+        |
             lowerBound = WindowRange()
         )
     ]
     [
-        <ALLOW> { pos = getPos(); } <PARTIAL> {
-            allowPartial = SqlLiteral.createBoolean(true, pos.plus(getPos()));
+        <ALLOW> { s2 = span(); } <PARTIAL> {
+            allowPartial = SqlLiteral.createBoolean(true, s2.end(this));
         }
     |
-        <DISALLOW> { pos = getPos(); } <PARTIAL> {
-            allowPartial = SqlLiteral.createBoolean(false, pos.plus(getPos()));
+        <DISALLOW> { s2 = span(); } <PARTIAL> {
+            allowPartial = SqlLiteral.createBoolean(false, s2.end(this));
         }
     ]
     <RPAREN>
     {
-        endPos = getPos();
         return SqlWindow.create(
             null, id, partitionList, orderList,
-            isRows, lowerBound, upperBound, allowPartial,
-            startPos.plus(endPos));
+            isRows, lowerBound, upperBound, allowPartial, s.end(this));
     }
 }
 
 SqlNode WindowRange() :
 {
-    SqlNode e;
-    SqlParserPos pos = null;
-    SqlParserPos endPos;
+    final SqlNode e;
+    final Span s;
 }
 {
-    <CURRENT> {pos = getPos();} <ROW>
-    {
-        endPos = getPos();
-        return SqlWindow.createCurrentRow(pos.plus(endPos));
+    <CURRENT> { s = span(); } <ROW> {
+        return SqlWindow.createCurrentRow(s.end(this));
     }
-    |
-    <UNBOUNDED>
-        { pos = getPos();}
+|
+    <UNBOUNDED> { s = span(); }
     (
-        <PRECEDING>
-        {
-            endPos = getPos();
-            return SqlWindow.createUnboundedPreceding(pos.plus(endPos));
+        <PRECEDING> {
+            return SqlWindow.createUnboundedPreceding(s.end(this));
         }
-        |
-        <FOLLOWING>
-        {
-            endPos = getPos();
-            return SqlWindow.createUnboundedFollowing(pos.plus(endPos));
+    |
+        <FOLLOWING> {
+            return SqlWindow.createUnboundedFollowing(s.end(this));
         }
     )
-    |
+|
     e = Expression(ExprContext.ACCEPT_NON_QUERY)
     (
-        <PRECEDING>
-        {
-            return SqlWindow.createPreceding(
-                e, getPos());
+        <PRECEDING> {
+            return SqlWindow.createPreceding(e, getPos());
         }
-        |
-        <FOLLOWING>
-        {
-            return SqlWindow.createFollowing(
-                e, getPos());
+    |
+        <FOLLOWING> {
+            return SqlWindow.createFollowing(e, getPos());
         }
     )
 }
@@ -2442,16 +2381,16 @@ SqlNodeList OrderBy(boolean accept) :
 {
     List<SqlNode> list;
     SqlNode e;
-    SqlParserPos pos;
+    final Span s;
 }
 {
     <ORDER> {
-        pos = getPos();
+        s = span();
         if (!accept) {
             // Someone told us ORDER BY wasn't allowed here.  So why
             // did they bother calling us?  To get the correct
             // parser position for error reporting.
-            throw SqlUtil.newContextException(pos, RESOURCE.illegalOrderBy());
+            throw SqlUtil.newContextException(s.pos(), RESOURCE.illegalOrderBy());
         }
     }
     <BY> e = OrderItem() {
@@ -2461,9 +2400,9 @@ SqlNodeList OrderBy(boolean accept) :
         // NOTE jvs 6-Feb-2004:  See comments at top of file for why
         // hint is necessary here.
         LOOKAHEAD(2) <COMMA> e = OrderItem() { list.add(e); }
-    ) *
+    )*
     {
-        return new SqlNodeList(list, pos.plusAll(list));
+        return new SqlNodeList(list, s.addAll(list).pos());
     }
 }
 
@@ -2501,48 +2440,47 @@ SqlNode OrderItem() :
  */
 SqlMatchRecognize MatchRecognizeOpt(SqlNode tableRef) :
 {
-    final SqlParserPos startPos;
+    final Span s, s1;
     SqlNodeList measureList = SqlNodeList.EMPTY;
     SqlNode pattern;
     SqlNodeList patternDefList;
     final SqlNode after;
-    final SqlParserPos pos;
     final SqlNode var;
     SqlNodeList subsetList = SqlNodeList.EMPTY;
     SqlLiteral isStrictStarts = SqlLiteral.createBoolean(false, getPos());
     SqlLiteral isStrictEnds = SqlLiteral.createBoolean(false, getPos());
 }
 {
-    <MATCH_RECOGNIZE> { startPos = getPos(); } <LPAREN>
+    <MATCH_RECOGNIZE> { s = span(); } <LPAREN>
     [
         <MEASURES>
-        measureList = MeasureColumnCommaList(getPos())
+        measureList = MeasureColumnCommaList(span())
     ]
     (
-        <AFTER> { pos = getPos(); } <MATCH> <SKIP_>
+        <AFTER> { s1 = span(); } <MATCH> <SKIP_>
         (
             <TO>
             (
                 LOOKAHEAD(2)
                 <NEXT> <ROW> {
                     after = SqlMatchRecognize.AfterOption.SKIP_TO_NEXT_ROW
-                        .symbol(pos.plus(getPos()));
+                        .symbol(s1.end(this));
                 }
             |
                 <FIRST> var = SimpleIdentifier() {
                     after = SqlMatchRecognize.SKIP_TO_FIRST.createCall(
-                        pos.plus(var.getParserPosition()), var);
+                        s1.end(var), var);
                 }
             |
                 [ <LAST> ] var = SimpleIdentifier() {
                     after = SqlMatchRecognize.SKIP_TO_LAST.createCall(
-                        pos.plus(var.getParserPosition()), var);
+                        s1.end(var), var);
                 }
             )
         |
             <PAST> <LAST> <ROW> {
                  after = SqlMatchRecognize.AfterOption.SKIP_PAST_LAST_ROW
-                     .symbol(pos.plus(getPos()));
+                     .symbol(s1.end(this));
             }
         )
     |
@@ -2564,18 +2502,18 @@ SqlMatchRecognize MatchRecognizeOpt(SqlNode tableRef) :
     <RPAREN>
     [
         <SUBSET>
-        subsetList = SubsetDefinitionCommaList(getPos())
+        subsetList = SubsetDefinitionCommaList(span())
     ]
     <DEFINE>
-    patternDefList = PatternDefinitionCommaList(getPos())
+    patternDefList = PatternDefinitionCommaList(span())
     <RPAREN> {
-        return new SqlMatchRecognize(startPos.plus(getPos()), tableRef,
+        return new SqlMatchRecognize(s.end(this), tableRef,
             pattern, isStrictStarts, isStrictEnds, patternDefList, measureList,
             after, subsetList);
     }
 }
 
-SqlNodeList MeasureColumnCommaList(SqlParserPos pos) :
+SqlNodeList MeasureColumnCommaList(Span s) :
 {
     SqlNode e;
     final List<SqlNode> eList = new ArrayList<SqlNode>();
@@ -2591,7 +2529,7 @@ SqlNodeList MeasureColumnCommaList(SqlParserPos pos) :
         }
     )*
     {
-        return new SqlNodeList(eList, pos.plusAll(eList));
+        return new SqlNodeList(eList, s.addAll(eList).pos());
     }
 }
 
@@ -2603,9 +2541,8 @@ SqlNode MeasureColumn() :
 {
     e = Expression(ExprContext.ACCEPT_NON_QUERY)
     <AS>
-    alias = SimpleIdentifier()
-    {
-        return SqlStdOperatorTable.AS.createCall(e.getParserPosition().plus(getPos()), e, alias);
+    alias = SimpleIdentifier() {
+        return SqlStdOperatorTable.AS.createCall(Span.of(e).end(this), e, alias);
     }
 }
 
@@ -2620,7 +2557,7 @@ SqlNode PatternExpression() :
         <VERTICAL_BAR>
         right = PatternTerm() {
             left = SqlStdOperatorTable.PATTERN_ALTER.createCall(
-                left.getParserPosition().plus(getPos()), left, right);
+                Span.of(left).end(right), left, right);
         }
     )*
     {
@@ -2638,7 +2575,7 @@ SqlNode PatternTerm() :
     (
         right = PatternFactor() {
             left = SqlStdOperatorTable.PATTERN_CONCAT.createCall(
-                left.getParserPosition().plus(getPos()), left, right);
+                Span.of(left).end(right), left, right);
         }
     )*
     {
@@ -2695,9 +2632,9 @@ SqlNode PatternFactor() :
             |
                 <MINUS> extra = PatternExpression() <MINUS> <RBRACE> {
                     extra = SqlStdOperatorTable.PATTERN_EXCLUDE.createCall(
-                        extra.getParserPosition().plus(getPos()), extra);
+                        Span.of(extra).end(this), extra);
                     e = SqlStdOperatorTable.PATTERN_CONCAT.createCall(
-                        e.getParserPosition().plus(getPos()), e, extra);
+                        Span.of(e).end(this), e, extra);
                     return e;
                 }
             )
@@ -2716,15 +2653,14 @@ SqlNode PatternFactor() :
             return e;
         } else {
             return SqlStdOperatorTable.PATTERN_QUANTIFIER.createCall(
-                e.getParserPosition().plus(getPos()),
-                e, startNum, endNum, reluctant);
+                span().end(e), e, startNum, endNum, reluctant);
         }
     }
 }
 
 SqlNode PatternPrimary() :
 {
-    SqlParserPos pos;
+    final Span s;
     SqlNode e;
     List<SqlNode> eList;
 }
@@ -2734,15 +2670,14 @@ SqlNode PatternPrimary() :
     |
         <LPAREN> e = PatternExpression() <RPAREN>
     |
-        <LBRACE> { pos = getPos(); }
+        <LBRACE> { s = span(); }
         <MINUS> e = PatternExpression()
         <MINUS> <RBRACE> {
-            e = SqlStdOperatorTable.PATTERN_EXCLUDE.createCall(
-                pos.plus(getPos()), e);
+            e = SqlStdOperatorTable.PATTERN_EXCLUDE.createCall(s.end(this), e);
         }
     |
         (
-            <PERMUTE> { pos = getPos(); }
+            <PERMUTE> { s = span(); }
             <LPAREN>
             e = PatternExpression() {
                 eList = new ArrayList<SqlNode>();
@@ -2757,7 +2692,7 @@ SqlNode PatternPrimary() :
             )*
             <RPAREN> {
                 e = SqlStdOperatorTable.PATTERN_PERMUTE.createCall(
-                    pos.plus(getPos()), eList);
+                    s.end(this), eList);
             }
         )
     )
@@ -2766,7 +2701,7 @@ SqlNode PatternPrimary() :
     }
 }
 
-SqlNodeList SubsetDefinitionCommaList(final SqlParserPos pos) :
+SqlNodeList SubsetDefinitionCommaList(Span s) :
 {
     SqlNode e;
     final List<SqlNode> eList = new ArrayList<SqlNode>();
@@ -2782,7 +2717,7 @@ SqlNodeList SubsetDefinitionCommaList(final SqlParserPos pos) :
         }
     )*
     {
-        return new SqlNodeList(eList, pos.plus(getPos()));
+        return new SqlNodeList(eList, s.addAll(eList).pos());
     }
 }
 
@@ -2795,14 +2730,14 @@ SqlNode SubsetDefinition() :
     var = SimpleIdentifier()
     <EQ>
     <LPAREN>
-    varList = ExpressionCommaList(null, ExprContext.ACCEPT_NON_QUERY)
+    varList = ExpressionCommaList(span(), ExprContext.ACCEPT_NON_QUERY)
     <RPAREN> {
-        return SqlStdOperatorTable.EQUALS.createCall(
-            var.getParserPosition().plus(getPos()), var, varList);
+        return SqlStdOperatorTable.EQUALS.createCall(span().end(var), var,
+            varList);
     }
 }
 
-SqlNodeList PatternDefinitionCommaList(SqlParserPos pos) :
+SqlNodeList PatternDefinitionCommaList(Span s) :
 {
     SqlNode e;
     final List<SqlNode> eList = new ArrayList<SqlNode>();
@@ -2818,21 +2753,20 @@ SqlNodeList PatternDefinitionCommaList(SqlParserPos pos) :
         }
     )*
     {
-        return new SqlNodeList(eList, pos.plusAll(eList));
+        return new SqlNodeList(eList, s.addAll(eList).pos());
     }
 }
 
 SqlNode PatternDefinition() :
 {
-    SqlNode var;
-    SqlNode e;
+    final SqlNode var;
+    final SqlNode e;
 }
 {
     var = SimpleIdentifier()
     <AS>
     e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
-        return SqlStdOperatorTable.AS.createCall(
-            var.getParserPosition().plus(getPos()), e, var);
+        return SqlStdOperatorTable.AS.createCall(Span.of(var, e).pos(), e, var);
     }
 }
 
@@ -2870,10 +2804,7 @@ SqlNode QueryOrExpr(ExprContext exprContext) :
     [
         withList = WithList()
     ]
-    (
-        e = LeafQueryOrExpr(exprContext)
-    )
-    {
+    e = LeafQueryOrExpr(exprContext) {
         list = startList(e);
     }
     (
@@ -2885,19 +2816,17 @@ SqlNode QueryOrExpr(ExprContext exprContext) :
                 checkNonQueryExpression(ExprContext.ACCEPT_QUERY);
             }
         }
-        op = BinaryQueryOperator()
-        {
+        op = BinaryQueryOperator() {
             // ensure a query is legal in this context
             pos = getPos();
             checkQueryExpression(exprContext);
 
         }
-        e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY)
-        {
+        e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY) {
             list.add(new SqlParserUtil.ToTreeListItem(op, pos));
             list.add(e);
         }
-    ) *
+    )*
     {
         e = SqlParserUtil.toTree(list);
         if (withList != null) {
@@ -2951,14 +2880,9 @@ SqlNode LeafQueryOrExpr(ExprContext exprContext) :
     SqlNode e;
 }
 {
-    e = Expression(exprContext)
-    {
-        return e;
-    }
-    | e = LeafQuery(exprContext)
-    {
-        return e;
-    }
+    e = Expression(exprContext) { return e; }
+|
+    e = LeafQuery(exprContext) { return e; }
 }
 
 /**
@@ -3017,7 +2941,7 @@ List<Object> Expression2(ExprContext exprContext) :
     SqlNodeList nodeList;
     SqlNode e;
     SqlOperator op;
-    SqlParserPos pos = getPos();
+    final Span s = span();
 }
 {
     Expression2b(exprContext, list)
@@ -3027,27 +2951,24 @@ List<Object> Expression2(ExprContext exprContext) :
             (
                 // Special case for "IN", because RHS of "IN" is the only place
                 // that an expression-list is allowed ("exp IN (exp1, exp2)").
-                LOOKAHEAD(2)
-                {
+                LOOKAHEAD(2) {
                     checkNonQueryExpression(exprContext);
                 }
                 (
-                    <NOT> <IN>
-                    {
+                    <NOT> <IN> {
                         op = SqlStdOperatorTable.NOT_IN;
-                        pos = getPos();
+                        s.clear().add(this);
                     }
                 |
-                    <IN>
-                    {
+                    <IN> {
                         op = SqlStdOperatorTable.IN;
-                        pos = getPos();
+                        s.clear().add(this);
                     }
                 )
                 nodeList = ParenthesizedQueryOrCommaList(ExprContext.ACCEPT_NONCURSOR)
                 {
-                    list.add(new SqlParserUtil.ToTreeListItem(op, pos));
-                    pos = pos.plus(getPos());
+                    list.add(new SqlParserUtil.ToTreeListItem(op, s.pos()));
+                    s.add(nodeList);
                     // special case for stuff like IN (s1 UNION s2)
                     if (nodeList.size() == 1) {
                         SqlNode item = nodeList.get(0);
@@ -3061,15 +2982,13 @@ List<Object> Expression2(ExprContext exprContext) :
                     }
                 }
             |
-                LOOKAHEAD(2)
-                {
+                LOOKAHEAD(2) {
                     checkNonQueryExpression(exprContext);
                 }
                 (
-                    <NOT> <BETWEEN>
-                    {
+                    <NOT> <BETWEEN> {
                         op = SqlStdOperatorTable.NOT_BETWEEN;
-                        pos = getPos();
+                        s.clear().add(this);
                     }
                     [
                         <SYMMETRIC> { op = SqlStdOperatorTable.SYMMETRIC_NOT_BETWEEN; }
@@ -3080,7 +2999,7 @@ List<Object> Expression2(ExprContext exprContext) :
                     <BETWEEN>
                     {
                         op = SqlStdOperatorTable.BETWEEN;
-                        pos = getPos();
+                        s.clear().add(this);
                     }
                     [
                         <SYMMETRIC> { op = SqlStdOperatorTable.SYMMETRIC_BETWEEN; }
@@ -3088,15 +3007,14 @@ List<Object> Expression2(ExprContext exprContext) :
                         <ASYMMETRIC>
                     ]
                 )
-                e = Expression3(ExprContext.ACCEPT_SUB_QUERY)
-                {
-                    list.add(new SqlParserUtil.ToTreeListItem(op, pos));
+                e = Expression3(ExprContext.ACCEPT_SUB_QUERY) {
+                    list.add(new SqlParserUtil.ToTreeListItem(op, s.pos()));
                     list.add(e);
                 }
             |
                 {
                     checkNonQueryExpression(exprContext);
-                    pos = getPos();
+                    s.clear().add(this);
                 }
                 (
                     <NOT>
@@ -3110,25 +3028,22 @@ List<Object> Expression2(ExprContext exprContext) :
                 |
                     <SIMILAR> <TO> { op = SqlStdOperatorTable.SIMILAR_TO; }
                 )
-                list2 = Expression2(ExprContext.ACCEPT_SUB_QUERY)
-                {
-                    list.add(new SqlParserUtil.ToTreeListItem(op, pos));
+                list2 = Expression2(ExprContext.ACCEPT_SUB_QUERY) {
+                    list.add(new SqlParserUtil.ToTreeListItem(op, s.pos()));
                     list.addAll(list2);
                 }
                 [
                     LOOKAHEAD(2)
-                    <ESCAPE> e = Expression3(ExprContext.ACCEPT_SUB_QUERY)
-                    {
-                        pos = getPos();
+                    <ESCAPE> e = Expression3(ExprContext.ACCEPT_SUB_QUERY) {
+                        s.clear().add(this);
                         list.add(
                             new SqlParserUtil.ToTreeListItem(
-                                SqlStdOperatorTable.ESCAPE, pos));
+                                SqlStdOperatorTable.ESCAPE, s.pos()));
                         list.add(e);
                     }
                 ]
             |
-                LOOKAHEAD(3) op = BinaryRowOperator()
-                {
+                LOOKAHEAD(3) op = BinaryRowOperator() {
                     checkNonQueryExpression(exprContext);
                     list.add(new SqlParserUtil.ToTreeListItem(op, getPos()));
                 }
@@ -3136,8 +3051,7 @@ List<Object> Expression2(ExprContext exprContext) :
             |
                 <LBRACKET>
                 e = Expression(ExprContext.ACCEPT_SUB_QUERY)
-                <RBRACKET>
-                {
+                <RBRACKET> {
                     list.add(
                         new SqlParserUtil.ToTreeListItem(
                             SqlStdOperatorTable.ITEM, getPos()));
@@ -3147,16 +3061,15 @@ List<Object> Expression2(ExprContext exprContext) :
                 {
                     checkNonQueryExpression(exprContext);
                 }
-                op = PostfixRowOperator()
-                {
+                op = PostfixRowOperator() {
                     list.add(new SqlParserUtil.ToTreeListItem(op, getPos()));
                 }
             )
-        ) +
+        )+
         {
             return list;
         }
-        |
+    |
         {
             return list;
         }
@@ -3174,8 +3087,8 @@ SqlNode Expression3(ExprContext exprContext) :
     final SqlNodeList list1;
     final SqlNodeList list2;
     final SqlOperator op;
-    final SqlParserPos pos;
-    SqlParserPos rowPos = null;
+    final Span s;
+    Span rowSpan = null;
 }
 {
     LOOKAHEAD(2)
@@ -3184,30 +3097,30 @@ SqlNode Expression3(ExprContext exprContext) :
         checkNonQueryExpression(exprContext);
         return e;
     }
-    |
+|
     e = CursorExpression(exprContext) { return e; }
-    |
+|
     LOOKAHEAD(3)
-    <ROW> list = ParenthesizedSimpleIdentifierList()
-    {
-        pos = getPos();
+    <ROW> {
+        s = span();
+    }
+    list = ParenthesizedSimpleIdentifierList() {
         if (exprContext != ExprContext.ACCEPT_ALL
             && exprContext != ExprContext.ACCEPT_CURSOR)
         {
-            throw SqlUtil.newContextException(pos,
+            throw SqlUtil.newContextException(s.end(list),
                 RESOURCE.illegalRowExpression());
         }
         return SqlStdOperatorTable.ROW.createCall(list);
     }
-    |
+|
     [
-        <ROW> { rowPos = getPos(); }
+        <ROW> { rowSpan = span(); }
     ]
     list1 = ParenthesizedQueryOrCommaList(exprContext) {
-        pos = list1.getParserPosition();
-        if (rowPos != null) {
+        if (rowSpan != null) {
             // interpret as row constructor
-            return SqlStdOperatorTable.ROW.createCall(rowPos.plus(pos),
+            return SqlStdOperatorTable.ROW.createCall(rowSpan.end(list1),
                 list1.toArray());
         }
     }
@@ -3232,7 +3145,7 @@ SqlNode Expression3(ExprContext exprContext) :
                     list1.toArray());
             }
         )
-        |
+    |
         */
         (
             e = IntervalQualifier()
@@ -3247,12 +3160,10 @@ SqlNode Expression3(ExprContext exprContext) :
                         list3.add(call.operand(1));
                         list3.add(e);
                         return SqlStdOperatorTable.MINUS_DATE.createCall(
-                            list1.getParserPosition().plus(getPos()),
-                            SqlParserUtil.toNodeArray(list3));
+                            Span.of(list1).end(this), list3);
                      }
                 }
-                throw SqlUtil.newContextException(
-                    list1.getParserPosition().plus(getPos()),
+                throw SqlUtil.newContextException(span().end(list1),
                     RESOURCE.illegalMinusDate());
             }
         )
@@ -3263,8 +3174,8 @@ SqlNode Expression3(ExprContext exprContext) :
             return list1.get(0);
         } else {
             // interpret as row constructor
-            return SqlStdOperatorTable.ROW.createCall(
-                pos.plus(list1.getParserPosition()), list1.toArray());
+            return SqlStdOperatorTable.ROW.createCall(span().end(list1),
+                list1.toArray());
         }
     }
 }
@@ -3305,49 +3216,51 @@ SqlCollation CollateClause() :
  */
 SqlNode AtomicRowExpression() :
 {
-    SqlNode e;
-    SqlParserPos pos;
+    final SqlNode e;
 }
 {
-    LOOKAHEAD(1)
-    e = Literal() { return e; }
+    (
+        LOOKAHEAD(1)
+        e = Literal()
     |
-    e = DynamicParam() { return e; }
+        e = DynamicParam()
     |
-    e = BuiltinFunctionCall() { return e; }
+        e = BuiltinFunctionCall()
     |
-    e = JdbcFunctionCall() { return e; }
+        e = JdbcFunctionCall()
     |
-    e = MultisetConstructor() { return e; }
+        e = MultisetConstructor()
     |
-    e = ArrayConstructor() { return e; }
+        e = ArrayConstructor()
     |
-    e = MapConstructor() { return e; }
+        e = MapConstructor()
     |
-    e = PeriodConstructor() { return e; }
+        e = PeriodConstructor()
     |
-    // NOTE jvs 18-Jan-2005:  use syntactic lookahead to discriminate
-    // compound identifiers from function calls in which the function
-    // name is a compound identifier
-    LOOKAHEAD( [<SPECIFIC>] FunctionName() <LPAREN>)
-    e = NamedFunctionCall() { return e; }
+        // NOTE jvs 18-Jan-2005:  use syntactic lookahead to discriminate
+        // compound identifiers from function calls in which the function
+        // name is a compound identifier
+        LOOKAHEAD( [<SPECIFIC>] FunctionName() <LPAREN>)
+        e = NamedFunctionCall()
     |
-    e = ContextVariable() { return e; }
+        e = ContextVariable()
     |
-    e = CompoundIdentifier() { return e; }
+        e = CompoundIdentifier()
     |
-    e = NewSpecification() { return e; }
+        e = NewSpecification()
     |
-    e = CaseExpression() { return e; }
+        e = CaseExpression()
     |
-    e = SequenceExpression() { return e; }
+        e = SequenceExpression()
+    )
+    { return e; }
 }
 
 SqlNode CaseExpression() :
 {
-    SqlParserPos whenPos;
-    SqlParserPos thenPos;
-    SqlParserPos pos;
+    final Span whenSpan = Span.of();
+    final Span thenSpan = Span.of();
+    final Span s;
     SqlNode e;
     SqlNode caseIdentifier = null;
     SqlNode elseClause = null;
@@ -3355,53 +3268,48 @@ SqlNode CaseExpression() :
     List<SqlNode> thenList = new ArrayList<SqlNode>();
 }
 {
-    <CASE>
-    {
-        pos = getPos();
-    }
+    <CASE> { s = span(); }
     [
         caseIdentifier = Expression(ExprContext.ACCEPT_SUB_QUERY)
     ]
     (
-        <WHEN>
-        { whenPos = getPos(); }
-        e = ExpressionCommaList(pos, ExprContext.ACCEPT_SUB_QUERY)
-        {
+        <WHEN> { whenSpan.add(this); }
+        e = ExpressionCommaList(s, ExprContext.ACCEPT_SUB_QUERY) {
             if (((SqlNodeList) e).size() == 1) {
                 e = ((SqlNodeList) e).get(0);
             }
             whenList.add(e);
         }
-        <THEN> e = Expression(ExprContext.ACCEPT_SUB_QUERY)
-        {  thenPos = getPos(); thenList.add(e); }
-    ) +
+        <THEN> { thenSpan.add(this); }
+        e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+            thenList.add(e);
+        }
+    )+
     [
         <ELSE> elseClause = Expression(ExprContext.ACCEPT_SUB_QUERY)
     ]
-    <END>
-    {
-        pos = pos.plus(getPos());
-        return SqlCase.createSwitched(pos, caseIdentifier,
-            new SqlNodeList(whenList, whenPos),
-            new SqlNodeList(thenList, thenPos),
+    <END> {
+        return SqlCase.createSwitched(s.end(this), caseIdentifier,
+            new SqlNodeList(whenList, whenSpan.addAll(whenList).pos()),
+            new SqlNodeList(thenList, thenSpan.addAll(thenList).pos()),
             elseClause);
     }
 }
 
 SqlCall SequenceExpression() :
 {
-    final SqlParserPos pos;
+    final Span s;
     final SqlOperator f;
     final SqlNode sequenceRef;
 }
 {
     (
-        <NEXT> { f = SqlStdOperatorTable.NEXT_VALUE; pos = getPos(); }
+        <NEXT> { f = SqlStdOperatorTable.NEXT_VALUE; s = span(); }
     |
-        <CURRENT> { f = SqlStdOperatorTable.CURRENT_VALUE; pos = getPos(); }
+        <CURRENT> { f = SqlStdOperatorTable.CURRENT_VALUE; s = span(); }
     )
     <VALUE> <FOR> sequenceRef = CompoundIdentifier() {
-        return f.createCall(pos, sequenceRef);
+        return f.createCall(s.end(sequenceRef), sequenceRef);
     }
 }
 
@@ -3409,7 +3317,7 @@ SqlCall SequenceExpression() :
  * Parses "SET &lt;NAME&gt; = VALUE" or "RESET &lt;NAME&gt;", without a leading
  * "ALTER &lt;SCOPE&gt;".
  */
-SqlSetOption SqlSetOption(SqlParserPos pos, String scope) :
+SqlSetOption SqlSetOption(Span s, String scope) :
 {
     SqlIdentifier name;
     final SqlNode val;
@@ -3417,7 +3325,7 @@ SqlSetOption SqlSetOption(SqlParserPos pos, String scope) :
 {
     (
         <SET> {
-            pos = pos == null ? getPos() : pos;
+            s.add(this);
         }
         name = CompoundIdentifier()
         <EQ>
@@ -3433,11 +3341,11 @@ SqlSetOption SqlSetOption(SqlParserPos pos, String scope) :
             }
         )
         {
-            return new SqlSetOption(pos.plus(getPos()), scope, name, val);
+            return new SqlSetOption(s.end(val), scope, name, val);
         }
     |
         <RESET> {
-            pos = pos == null ? getPos() : pos;
+            s.add(this);
         }
         (
             name = CompoundIdentifier()
@@ -3448,7 +3356,7 @@ SqlSetOption SqlSetOption(SqlParserPos pos, String scope) :
             }
         )
         {
-            return new SqlSetOption(pos.plus(getPos()), scope, name, null);
+            return new SqlSetOption(s.end(name), scope, name, null);
         }
     )
 }
@@ -3459,23 +3367,21 @@ SqlSetOption SqlSetOption(SqlParserPos pos, String scope) :
  */
 SqlAlter SqlAlter() :
 {
-    final SqlParserPos pos;
+    final Span s;
     final String scope;
     final SqlAlter alterNode;
 }
 {
+    <ALTER> { s = span(); }
+    scope = Scope()
     (
-        <ALTER> { pos = getPos(); }
-        scope = Scope()
-    )
-    (
-        alterNode = SqlSetOption(pos, scope)
+        alterNode = SqlSetOption(s, scope)
 
-  <#-- additional literal parser methods are included here -->
-  <#list parser.alterStatementParserMethods as method>
+<#-- additional literal parser methods are included here -->
+<#list parser.alterStatementParserMethods as method>
     |
-        alterNode = ${method}(pos, scope)
-  </#list>
+        alterNode = ${method}(s, scope)
+</#list>
     )
     {
         return alterNode;
@@ -3495,23 +3401,23 @@ String Scope() :
  */
 SqlCreate SqlCreate() :
 {
-    final SqlParserPos pos;
+    final Span s;
     boolean replace = false;
     final SqlCreate create;
 }
 {
-    <CREATE> { pos = getPos(); }
+    <CREATE> { s = span(); }
     [
         <OR> <REPLACE> {
             replace = true;
         }
     ]
     (
-    <#-- additional literal parser methods are included here -->
-    <#list parser.createStatementParserMethods as method>
-        create = ${method}(pos, replace)
+<#-- additional literal parser methods are included here -->
+<#list parser.createStatementParserMethods as method>
+        create = ${method}(s, replace)
         <#sep>|</#sep>
-    </#list>
+</#list>
     )
     {
         return create;
@@ -3525,18 +3431,18 @@ SqlCreate SqlCreate() :
  */
 SqlDrop SqlDrop() :
 {
-    final SqlParserPos pos;
+    final Span s;
     boolean replace = false;
     final SqlDrop drop;
 }
 {
-    <DROP> { pos = getPos(); }
+    <DROP> { s = span(); }
     (
-    <#-- additional literal parser methods are included here -->
-    <#list parser.dropStatementParserMethods as method>
-        drop = ${method}(pos, replace)
+<#-- additional literal parser methods are included here -->
+<#list parser.dropStatementParserMethods as method>
+        drop = ${method}(s, replace)
         <#sep>|</#sep>
-    </#list>
+</#list>
     )
     {
         return drop;
@@ -3557,19 +3463,19 @@ SqlNode Literal() :
 {
     (
         e = NumericLiteral()
-        |
+    |
         e = StringLiteral()
-        |
+    |
         e = SpecialLiteral()
-        |
+    |
         e = DateTimeLiteral()
-        |
+    |
         e = IntervalLiteral()
-      <#-- additional literal parser methods are included here -->
-      <#list parser.literalParserMethods as method>
-        |
+<#-- additional literal parser methods are included here -->
+<#list parser.literalParserMethods as method>
+    |
         e = ${method}
-      </#list>
+</#list>
     )
     {
         return e;
@@ -3583,18 +3489,15 @@ SqlNumericLiteral UnsignedNumericLiteral() :
 {
 }
 {
-    <UNSIGNED_INTEGER_LITERAL>
-    {
+    <UNSIGNED_INTEGER_LITERAL> {
         return SqlLiteral.createExactNumeric(token.image, getPos());
     }
-    |
-    <DECIMAL_NUMERIC_LITERAL>
-    {
+|
+    <DECIMAL_NUMERIC_LITERAL> {
         return SqlLiteral.createExactNumeric(token.image, getPos());
     }
-    |
-    <APPROX_NUMERIC_LITERAL>
-    {
+|
+    <APPROX_NUMERIC_LITERAL> {
         return SqlLiteral.createApproxNumeric(token.image, getPos());
     }
 }
@@ -3602,22 +3505,19 @@ SqlNumericLiteral UnsignedNumericLiteral() :
 /** Parses a numeric literal (can be signed) */
 SqlLiteral NumericLiteral() :
 {
-    SqlNumericLiteral num;
-    SqlParserPos pos;
+    final SqlNumericLiteral num;
+    final Span s;
 }
 {
-    <PLUS> num = UnsignedNumericLiteral()
-    {
+    <PLUS> num = UnsignedNumericLiteral() {
         return num;
     }
-    |
-    <MINUS> { pos = getPos(); } num = UnsignedNumericLiteral()
-    {
-        return SqlLiteral.createNegative(num, pos.plus(getPos()));
+|
+    <MINUS> { s = span(); } num = UnsignedNumericLiteral() {
+        return SqlLiteral.createNegative(num, s.end(this));
     }
-    |
-    num = UnsignedNumericLiteral()
-    {
+|
+    num = UnsignedNumericLiteral() {
         return num;
     }
 }
@@ -3628,11 +3528,11 @@ SqlLiteral SpecialLiteral() :
 }
 {
     <TRUE> { return SqlLiteral.createBoolean(true, getPos()); }
-    |
+|
     <FALSE> { return SqlLiteral.createBoolean(false, getPos()); }
-    |
+|
     <UNKNOWN> { return SqlLiteral.createUnknown(getPos()); }
-    |
+|
     <NULL> { return SqlLiteral.createNull(getPos()); }
 }
 
@@ -3684,7 +3584,7 @@ SqlNode StringLiteral() :
                     RESOURCE.illegalBinaryString(token.image));
             }
         }
-    ) *
+    )*
     {
         assert (nfrags > 0);
         if (nfrags == 1) {
@@ -3701,9 +3601,8 @@ SqlNode StringLiteral() :
     (
         <PREFIXED_STRING_LITERAL>
         { charSet = SqlParserUtil.getCharacterSet(token.image); }
-        | <QUOTED_STRING>
-        | <UNICODE_STRING_LITERAL>
-        {
+    |   <QUOTED_STRING>
+    |   <UNICODE_STRING_LITERAL> {
             // TODO jvs 2-Feb-2009:  support the explicit specification of
             // a character set for Unicode string literals, per SQL:2003
             unicodeEscapeChar = BACKSLASH;
@@ -3735,9 +3634,7 @@ SqlNode StringLiteral() :
             frags.add(literal);
             nfrags++;
         }
-    ) *
-    {
-    }
+    )*
     [
         <UESCAPE> <QUOTED_STRING>
         {
@@ -3750,8 +3647,6 @@ SqlNode StringLiteral() :
         }
     ]
     {
-    }
-    {
         assert nfrags > 0;
         if (nfrags == 1) {
             // just the head fragment
@@ -3775,50 +3670,41 @@ SqlNode StringLiteral() :
  */
 SqlLiteral DateTimeLiteral() :
 {
-    String  p;
-    SqlParserPos pos;
+    final String  p;
+    final Span s;
 }
 {
-    <LBRACE_D> <QUOTED_STRING>
-    {
+    <LBRACE_D> <QUOTED_STRING> {
         p = token.image;
     }
-    <RBRACE>
-    {
+    <RBRACE> {
         return parseDateLiteral(p, getPos());
     }
-    |
-    <LBRACE_T> <QUOTED_STRING>
-    {
+|
+    <LBRACE_T> <QUOTED_STRING> {
         p = token.image;
     }
-    <RBRACE>
-    {
+    <RBRACE> {
         return parseTimeLiteral(p, getPos());
     }
-    |
-    <LBRACE_TS> <QUOTED_STRING>
-    {
+|
+    <LBRACE_TS> { s = span(); } <QUOTED_STRING> {
         p = token.image;
     }
-    <RBRACE>
-    {
-        return parseTimestampLiteral(p, getPos());
+    <RBRACE> {
+        return parseTimestampLiteral(p, s.end(this));
     }
-    |
-    <DATE> { pos = getPos(); } <QUOTED_STRING>
-    {
-        return parseDateLiteral(token.image, pos.plus(getPos()));
+|
+    <DATE> { s = span(); } <QUOTED_STRING> {
+        return parseDateLiteral(token.image, s.end(this));
     }
-    |
-    <TIME> { pos = getPos(); } <QUOTED_STRING>
-    {
-        return parseTimeLiteral(token.image, pos.plus(getPos()));
+|
+    <TIME> { s = span(); } <QUOTED_STRING> {
+        return parseTimeLiteral(token.image, s.end(this));
     }
-    |
-    <TIMESTAMP> { pos = getPos(); } <QUOTED_STRING>
-    {
-        return parseTimestampLiteral(token.image, pos.plus(getPos()));
+|
+    <TIMESTAMP> { s = span(); } <QUOTED_STRING> {
+        return parseTimestampLiteral(token.image, s.end(this));
     }
 }
 
@@ -3827,19 +3713,18 @@ SqlNode MultisetConstructor() :
 {
     List<SqlNode> args;
     SqlNode e;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <MULTISET> { pos = getPos(); }
+    <MULTISET> { s = span(); }
     (
         LOOKAHEAD(1)
         <LPAREN>
         // by sub query "MULTISET(SELECT * FROM T)"
         e = LeafQueryOrExpr(ExprContext.ACCEPT_QUERY)
-        <RPAREN>
-        {
+        <RPAREN> {
             return SqlStdOperatorTable.MULTISET_QUERY.createCall(
-                pos.plus(getPos()), e);
+                s.end(this), e);
         }
     |
         // by enumeration "MULTISET[e0, e1, ..., eN]"
@@ -3847,11 +3732,11 @@ SqlNode MultisetConstructor() :
         e = Expression(ExprContext.ACCEPT_NON_QUERY) { args = startList(e); }
         (
             <COMMA> e = Expression(ExprContext.ACCEPT_NON_QUERY) { args.add(e); }
-        ) *
+        )*
         <RBRACKET>
         {
             return SqlStdOperatorTable.MULTISET_VALUE.createCall(
-                pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+                s.end(this), args);
         }
     )
 }
@@ -3861,10 +3746,10 @@ SqlNode ArrayConstructor() :
 {
     SqlNodeList args;
     SqlNode e;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <ARRAY> { pos = getPos(); }
+    <ARRAY> { s = span(); }
     (
         LOOKAHEAD(1)
         <LPAREN>
@@ -3873,20 +3758,20 @@ SqlNode ArrayConstructor() :
         <RPAREN>
         {
             return SqlStdOperatorTable.ARRAY_QUERY.createCall(
-                pos.plus(getPos()), e);
+                s.end(this), e);
         }
     |
         // by enumeration "ARRAY[e0, e1, ..., eN]"
         <LBRACKET> // TODO: do trigraph as well ??( ??)
         (
-            args = ExpressionCommaList(pos, ExprContext.ACCEPT_NON_QUERY)
+            args = ExpressionCommaList(s, ExprContext.ACCEPT_NON_QUERY)
         |
-            { args = new SqlNodeList(getPos()); }
+            { args = SqlNodeList.EMPTY; }
         )
         <RBRACKET>
         {
             return SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR.createCall(
-                pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+                s.end(this), args.getList());
         }
     )
 }
@@ -3896,10 +3781,10 @@ SqlNode MapConstructor() :
 {
     SqlNodeList args;
     SqlNode e;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <MAP> { pos = getPos(); }
+    <MAP> { s = span(); }
     (
         LOOKAHEAD(1)
         <LPAREN>
@@ -3908,20 +3793,20 @@ SqlNode MapConstructor() :
         <RPAREN>
         {
             return SqlStdOperatorTable.MAP_QUERY.createCall(
-                pos.plus(getPos()), e);
+                s.end(this), e);
         }
     |
         // by enumeration "MAP[k0, v0, ..., kN, vN]"
         <LBRACKET> // TODO: do trigraph as well ??( ??)
         (
-            args = ExpressionCommaList(pos, ExprContext.ACCEPT_NON_QUERY)
+            args = ExpressionCommaList(s, ExprContext.ACCEPT_NON_QUERY)
         |
-            { args = new SqlNodeList(getPos()); }
+            { args = SqlNodeList.EMPTY; }
         )
         <RBRACKET>
         {
             return SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR.createCall(
-                pos.plus(getPos()), SqlParserUtil.toNodeArray(args));
+                s.end(this), args.getList());
         }
     )
 }
@@ -3930,16 +3815,16 @@ SqlNode MapConstructor() :
 SqlNode PeriodConstructor() :
 {
     final SqlNode e0, e1;
-    final SqlParserPos pos;
+    final Span s;
 }
 {
-    <PERIOD> { pos = getPos(); }
+    <PERIOD> { s = span(); }
     <LPAREN>
     e0 = Expression(ExprContext.ACCEPT_SUB_QUERY)
     <COMMA>
     e1 = Expression(ExprContext.ACCEPT_SUB_QUERY)
     <RPAREN> {
-        return SqlStdOperatorTable.ROW.createCall(pos.plus(getPos()), e0, e1);
+        return SqlStdOperatorTable.ROW.createCall(s.end(this), e0, e1);
     }
 }
 
@@ -3948,22 +3833,22 @@ SqlNode PeriodConstructor() :
  */
 SqlLiteral IntervalLiteral() :
 {
-    String p;
-    SqlIntervalQualifier intervalQualifier;
+    final String p;
+    final SqlIntervalQualifier intervalQualifier;
     int sign = 1;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    <INTERVAL> { pos = getPos(); }
+    <INTERVAL> { s = span(); }
     [
         <MINUS> { sign = -1; }
     |
         <PLUS> { sign = 1; }
     ]
     <QUOTED_STRING> { p = token.image; }
-    intervalQualifier = IntervalQualifier()
-    {
-        return parseIntervalLiteral(pos.plus(getPos()), sign, p, intervalQualifier);
+    intervalQualifier = IntervalQualifier() {
+        return parseIntervalLiteral(s.end(intervalQualifier), sign, p,
+            intervalQualifier);
     }
 }
 
@@ -3984,31 +3869,34 @@ SqlIntervalQualifier IntervalQualifier() :
             }
         ]
         { start = TimeUnit.YEAR; }
-        |
+    |
         <MONTH> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
         { start = TimeUnit.MONTH; }
-        |
+    |
         <DAY> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
         [ LOOKAHEAD(2) <TO>
             (
                 <HOUR> { end = TimeUnit.HOUR; }
-                | <MINUTE> { end = TimeUnit.MINUTE; }
-                | <SECOND> { end = TimeUnit.SECOND; }
+            |
+                <MINUTE> { end = TimeUnit.MINUTE; }
+            |
+                <SECOND> { end = TimeUnit.SECOND; }
                 [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ]
             )
         ]
         { start = TimeUnit.DAY; }
-        |
+    |
         <HOUR> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
         [ LOOKAHEAD(2) <TO>
             (
                 <MINUTE> { end = TimeUnit.MINUTE; }
-                | <SECOND> { end = TimeUnit.SECOND; }
+            |
+                <SECOND> { end = TimeUnit.SECOND; }
                 [ <LPAREN> secondFracPrec = UnsignedIntLiteral() <RPAREN> ]
             )
         ]
         { start = TimeUnit.HOUR; }
-        |
+    |
         <MINUTE> [ <LPAREN> startPrec = UnsignedIntLiteral() <RPAREN> ]
         [ LOOKAHEAD(2) <TO>
             (
@@ -4017,7 +3905,7 @@ SqlIntervalQualifier IntervalQualifier() :
             )
         ]
         { start = TimeUnit.MINUTE; }
-        |
+    |
         <SECOND>
         [   <LPAREN> startPrec = UnsignedIntLiteral()
             [ <COMMA> secondFracPrec = UnsignedIntLiteral() ]
@@ -4088,13 +3976,10 @@ TimeUnit TimestampInterval() :
  */
 SqlDynamicParam DynamicParam() :
 {
-    SqlParserPos pos;
 }
 {
-    <HOOK>
-    {
-        pos = getPos();
-        return new SqlDynamicParam(nDynamicParams++, pos);
+    <HOOK> {
+        return new SqlDynamicParam(nDynamicParams++, getPos());
     }
 }
 
@@ -4113,41 +3998,40 @@ String Identifier() :
         {
             id = unquotedIdentifier();
         }
-        | <QUOTED_IDENTIFIER>
-        {
+    |
+        <QUOTED_IDENTIFIER> {
             id = SqlParserUtil.strip(getToken(0).image, DQ, DQ, DQDQ,
                 quotedCasing);
         }
-        | <BACK_QUOTED_IDENTIFIER>
-        {
+    |
+        <BACK_QUOTED_IDENTIFIER> {
             id = SqlParserUtil.strip(getToken(0).image, "`", "`", "``",
                 quotedCasing);
         }
-        | <BRACKET_QUOTED_IDENTIFIER>
-        {
+    |
+        <BRACKET_QUOTED_IDENTIFIER> {
             id = SqlParserUtil.strip(getToken(0).image, "[", "]", "]]",
                 quotedCasing);
         }
-        | <UNICODE_QUOTED_IDENTIFIER>
-        {
+    |
+        <UNICODE_QUOTED_IDENTIFIER> {
             id = getToken(0).image;
             id = id.substring(id.indexOf('"'));
             id = SqlParserUtil.strip(id, DQ, DQ, DQDQ, quotedCasing);
         }
-        [ <UESCAPE> <QUOTED_STRING>
-            {
+        [
+            <UESCAPE> <QUOTED_STRING> {
                 String s = SqlParserUtil.parseString(token.image);
                 unicodeEscapeChar = SqlParserUtil.checkUnicodeEscapeChar(s);
             }
         ]
         {
-        }
-        {
             SqlLiteral lit = SqlLiteral.createCharString(id, "UTF16", getPos());
             lit = lit.unescapeUnicode(unicodeEscapeChar);
             return lit.toValue();
         }
-        | id = NonReservedKeyWord()
+    |
+        id = NonReservedKeyWord()
     )
     {
         if (id.length() > this.identifierMaxLength) {
@@ -4163,13 +4047,11 @@ String Identifier() :
  */
 SqlIdentifier SimpleIdentifier() :
 {
-    String p;
-    SqlParserPos pos;
+    final String p;
 }
 {
-    p = Identifier(){pos = getPos();}
-    {
-        return new SqlIdentifier(p,pos);
+    p = Identifier() {
+        return new SqlIdentifier(p, getPos());
     }
 }
 
@@ -4182,7 +4064,11 @@ void SimpleIdentifierCommaList(List<SqlNode> list) :
 }
 {
     id = SimpleIdentifier() {list.add(id);}
-    (<COMMA> id = SimpleIdentifier() {list.add(id);}) *
+    (
+        <COMMA> id = SimpleIdentifier() {
+            list.add(id);
+        }
+    )*
 }
 
 /**
@@ -4191,15 +4077,14 @@ void SimpleIdentifierCommaList(List<SqlNode> list) :
   */
 SqlNodeList ParenthesizedSimpleIdentifierList() :
 {
-    SqlParserPos pos;
-    List<SqlNode> list = new ArrayList<SqlNode>();
+    final Span s;
+    final List<SqlNode> list = new ArrayList<SqlNode>();
 }
 {
-    <LPAREN> { pos = getPos(); }
+    <LPAREN> { s = span(); }
     SimpleIdentifierCommaList(list)
-    <RPAREN>
-    {
-        return new SqlNodeList(list, pos.plus(getPos()));
+    <RPAREN> {
+        return new SqlNodeList(list, s.end(this));
     }
 }
 
@@ -4226,7 +4111,7 @@ SqlIdentifier CompoundIdentifier() :
             list.add(p);
             posList.add(getPos());
         }
-    ) *
+    )*
     (
         <DOT>
         <STAR> {
@@ -4253,7 +4138,7 @@ void CompoundIdentifierCommaList(List<SqlNode> list) :
 }
 {
     id = CompoundIdentifier() {list.add(id);}
-    (<COMMA> id = CompoundIdentifier() {list.add(id);}) *
+    (<COMMA> id = CompoundIdentifier() {list.add(id);})*
 }
 
 /**
@@ -4262,15 +4147,14 @@ void CompoundIdentifierCommaList(List<SqlNode> list) :
   */
 SqlNodeList ParenthesizedCompoundIdentifierList() :
 {
-    SqlParserPos pos;
-    List<SqlNode> list = new ArrayList<SqlNode>();
+    final Span s;
+    final List<SqlNode> list = new ArrayList<SqlNode>();
 }
 {
-    <LPAREN> { pos = getPos(); }
+    <LPAREN> { s = span(); }
     CompoundIdentifierCommaList(list)
-    <RPAREN>
-    {
-        return new SqlNodeList(list, pos.plus(getPos()));
+    <RPAREN> {
+        return new SqlNodeList(list, s.end(this));
     }
 }
 <#else>
@@ -4282,20 +4166,15 @@ SqlNodeList ParenthesizedCompoundIdentifierList() :
  */
 SqlNode NewSpecification() :
 {
-    SqlParserPos callPos;
-    SqlNode routineCall;
+    final Span s;
+    final SqlNode routineCall;
 }
 {
-    <NEW>
-    {
-        callPos = getPos();
-    }
+    <NEW> { s = span(); }
     routineCall =
-    NamedRoutineCall(
-        SqlFunctionCategory.USER_DEFINED_CONSTRUCTOR,
-        ExprContext.ACCEPT_SUB_QUERY)
-    {
-        return SqlStdOperatorTable.NEW.createCall(callPos, routineCall);
+        NamedRoutineCall(SqlFunctionCategory.USER_DEFINED_CONSTRUCTOR,
+            ExprContext.ACCEPT_SUB_QUERY) {
+        return SqlStdOperatorTable.NEW.createCall(s.end(routineCall), routineCall);
     }
 }
 
@@ -4320,7 +4199,11 @@ int IntLiteral() :
     Token t;
 }
 {
-    ( t = <UNSIGNED_INTEGER_LITERAL> | <PLUS> t = <UNSIGNED_INTEGER_LITERAL> )
+    (
+        t = <UNSIGNED_INTEGER_LITERAL>
+    |
+        <PLUS> t = <UNSIGNED_INTEGER_LITERAL>
+    )
     {
         try {
             return Integer.parseInt(t.image);
@@ -4328,9 +4211,8 @@ int IntLiteral() :
             throw generateParseException();
         }
     }
-    |
-    <MINUS> t = <UNSIGNED_INTEGER_LITERAL>
-    {
+|
+    <MINUS> t = <UNSIGNED_INTEGER_LITERAL> {
         try {
             return -Integer.parseInt(t.image);
         } catch (NumberFormatException ex) {
@@ -4342,36 +4224,33 @@ int IntLiteral() :
 // Type name with optional scale and precision
 SqlDataTypeSpec DataType() :
 {
-    SqlIdentifier typeName;
+    final SqlIdentifier typeName;
     SqlIdentifier collectionTypeName = null;
     int scale = -1;
     int precision = -1;
     String charSetName = null;
-    SqlParserPos pos;
+    final Span s;
 }
 {
-    (
-        typeName = TypeName()
-        {
-            pos = getPos();
-        }
-        [
-            <LPAREN>
-            precision = UnsignedIntLiteral()
-            [
-                <COMMA>
-                scale = UnsignedIntLiteral()
-            ]
-            <RPAREN>
-        ]
-        [
-            <CHARACTER> <SET>
-            charSetName = Identifier()
-        ]
+    typeName = TypeName() {
+        s = span();
+    }
+    [
+        <LPAREN>
+        precision = UnsignedIntLiteral()
         [
-            collectionTypeName = CollectionsTypeName()
+            <COMMA>
+            scale = UnsignedIntLiteral()
         ]
-    )
+        <RPAREN>
+    ]
+    [
+        <CHARACTER> <SET>
+        charSetName = Identifier()
+    ]
+    [
+        collectionTypeName = CollectionsTypeName()
+    ]
     {
         if (null != collectionTypeName) {
             return new SqlDataTypeSpec(
@@ -4380,7 +4259,7 @@ SqlDataTypeSpec DataType() :
                 precision,
                 scale,
                 charSetName,
-                pos);
+                s.end(collectionTypeName));
         }
         return new SqlDataTypeSpec(
             typeName,
@@ -4388,7 +4267,7 @@ SqlDataTypeSpec DataType() :
             scale,
             charSetName,
             null,
-            pos);
+            s.end(this));
     }
 }
 
@@ -4396,124 +4275,24 @@ 

<TRUNCATED>

Mime
View raw message