Repository: cloudspannerecosystem/memefish (go)

Issue:
InvalidPos handling of ARRAY keyword in ArrayLiteral seems wrong
`ARRAY` is always printed in `ArrayLiteral`, even if `ARRAY` keyword is not used.
```
$ go run ./tools/parse --mode expr '[]'     
--- AST
&ast.ArrayLiteral{
  Array:  0,
  Lbrack: 0,
  Rbrack: 1,
  Type:   nil,
  Values: []ast.Expr(nil),
}

--- SQL
ARRAY[]
$ go run ./tools/parse --mode expr 'ARRAY[]'
--- AST
&ast.ArrayLiteral{
  Array:  0,
  Lbrack: 5,
  Rbrack: 6,
  Type:   nil,
  Values: []ast.Expr(nil),
}

--- SQL
ARRAY[]
```

I believe it should also be fixed because `Array.Invalid()` is handled

https://github.com/cloudspannerecosystem/memefish/blob/ad392f19203b64436c2a14cf0f079cf949c4f899/ast/pos.go#L418-L421

but `token.InvalidPos` is not set in `parseSimpleArrayLiteral()`.

https://github.com/cloudspannerecosystem/memefish/blob/ad392f19203b64436c2a14cf0f079cf949c4f899/parser.go#L1759-L1765

Pull request:
Fix InvalidPos handling of ARRAY keyword in ArrayLiteral
fixes #144 

This PR fixes the spec of `ArrayLiteral.SQL()` to preserve lexical tokens.
```
$ go run ./tools/parse --mode expr '[]'     
--- AST
&ast.ArrayLiteral{
  Array:  -1,
  Lbrack: 0,
  Rbrack: 1,
  Type:   nil,
  Values: []ast.Expr(nil),
}

--- SQL
[]
```
```
$ go run ./tools/parse --mode expr 'ARRAY[]'
--- AST
&ast.ArrayLiteral{
  Array:  0,
  Lbrack: 5,
  Rbrack: 6,
  Type:   nil,
  Values: []ast.Expr(nil),
}

--- SQL
ARRAY[]
```
```
$ go run ./tools/parse --mode expr 'ARRAY<INT64>[]'
--- AST
&ast.ArrayLiteral{
  Array:  0,
  Lbrack: 12,
  Rbrack: 13,
  Type:   &ast.SimpleType{
    NamePos: 6,
    Name:    "INT64",
  },
  Values: []ast.Expr(nil),
}

--- SQL
ARRAY<INT64>[]
```

Patch:
diff --git a/ast/ast.go b/ast/ast.go
index 4c0c867..ba0da57 100644
--- a/ast/ast.go
+++ b/ast/ast.go
@@ -1232,14 +1232,14 @@ type Path struct {
 	Idents []*Ident // len(Idents) >= 2
 }
 
-// AraryLiteral is array literal node.
+// ArrayLiteral is array literal node.
 //
-//	ARRAY{{if .Type}}<{{.Type | sql}}>{{end}}[{{.Values | sqlJoin ","}}]
+//	{{if .Array.Invalid | not}}ARRAY{{end}}{{if .Type}}<{{.Type | sql}}>{{end}}[{{.Values | sqlJoin ","}}]
 type ArrayLiteral struct {
 	// pos = Array || Lbrack
 	// end = Rbrack + 1
 
-	Array          token.Pos // position of "ARRAY" keyword
+	Array          token.Pos // position of "ARRAY" keyword, optional
 	Lbrack, Rbrack token.Pos // position of "[" and "]"
 
 	Type   Type // optional
diff --git a/ast/sql.go b/ast/sql.go
index 4eb9ef3..bf913bb 100644
--- a/ast/sql.go
+++ b/ast/sql.go
@@ -620,19 +620,9 @@ func (p *Path) SQL() string {
 }
 
 func (a *ArrayLiteral) SQL() string {
-	sql := "ARRAY"
-	if a.Type != nil {
-		sql += "<" + a.Type.SQL() + ">"
-	}
-	sql += "["
-	for i, v := range a.Values {
-		if i != 0 {
-			sql += ", "
-		}
-		sql += v.SQL()
-	}
-	sql += "]"
-	return sql
+	return strOpt(!a.Array.Invalid(), "ARRAY") +
+		sqlOpt("<", a.Type, ">") +
+		"[" + sqlJoin(a.Values, ", ") + "]"
 }
 
 func (s *StructLiteral) SQL() string {
diff --git a/parser.go b/parser.go
index c734cfc..24ad76a 100644
--- a/parser.go
+++ b/parser.go
@@ -1759,6 +1759,7 @@ func (p *Parser) parseArrayLiteralOrSubQuery() ast.Expr {
 func (p *Parser) parseSimpleArrayLiteral() *ast.ArrayLiteral {
 	values, lbrack, rbrack := p.parseArrayLiteralBody()
 	return &ast.ArrayLiteral{
+		Array:  token.InvalidPos,
 		Lbrack: lbrack,
 		Rbrack: rbrack,
 		Values: values,


Test patch:
diff --git a/testdata/input/expr/array_literal_empty_with_types.sql b/testdata/input/expr/array_literal_empty_with_types.sql
new file mode 100644
index 0000000..925ab43
--- /dev/null
+++ b/testdata/input/expr/array_literal_empty_with_types.sql
@@ -0,0 +1,1 @@
+ARRAY<INT64>[]
\ No newline at end of file
diff --git a/testdata/input/expr/array_literal_empty_without_array_keyword.sql b/testdata/input/expr/array_literal_empty_without_array_keyword.sql
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/testdata/input/expr/array_literal_empty_without_array_keyword.sql
@@ -0,0 +1,1 @@
+[]
\ No newline at end of file
diff --git a/testdata/input/expr/array_literal_empty_without_types.sql b/testdata/input/expr/array_literal_empty_without_types.sql
new file mode 100644
index 0000000..eb96d7d
--- /dev/null
+++ b/testdata/input/expr/array_literal_empty_without_types.sql
@@ -0,0 +1,1 @@
+ARRAY[]
\ No newline at end of file
diff --git a/testdata/result/dml/insert_select.sql.txt b/testdata/result/dml/insert_select.sql.txt
index f7da01d..778f124 100644
--- a/testdata/result/dml/insert_select.sql.txt
+++ b/testdata/result/dml/insert_select.sql.txt
@@ -39,7 +39,7 @@ select * from unnest([(1, 2), (3, 4)])
           Rparen:   59,
           Implicit: false,
           Expr:     &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 43,
             Rbrack: 58,
             Type:   nil,
@@ -102,4 +102,4 @@ select * from unnest([(1, 2), (3, 4)])
 }
 
 --- SQL
-INSERT INTO foo (foo, bar) SELECT * FROM UNNEST(ARRAY[STRUCT(1, 2), STRUCT(3, 4)])
+INSERT INTO foo (foo, bar) SELECT * FROM UNNEST([STRUCT(1, 2), STRUCT(3, 4)])
diff --git a/testdata/result/expr/array_literal_empty_with_types.sql.txt b/testdata/result/expr/array_literal_empty_with_types.sql.txt
new file mode 100644
index 0000000..4936cbb
--- /dev/null
+++ b/testdata/result/expr/array_literal_empty_with_types.sql.txt
@@ -0,0 +1,16 @@
+--- array_literal_empty_with_types.sql
+ARRAY<INT64>[]
+--- AST
+&ast.ArrayLiteral{
+  Array:  0,
+  Lbrack: 12,
+  Rbrack: 13,
+  Type:   &ast.SimpleType{
+    NamePos: 6,
+    Name:    "INT64",
+  },
+  Values: []ast.Expr(nil),
+}
+
+--- SQL
+ARRAY<INT64>[]
diff --git a/testdata/result/expr/array_literal_empty_without_array_keyword.sql.txt b/testdata/result/expr/array_literal_empty_without_array_keyword.sql.txt
new file mode 100644
index 0000000..5f36885
--- /dev/null
+++ b/testdata/result/expr/array_literal_empty_without_array_keyword.sql.txt
@@ -0,0 +1,13 @@
+--- array_literal_empty_without_array_keyword.sql
+[]
+--- AST
+&ast.ArrayLiteral{
+  Array:  -1,
+  Lbrack: 0,
+  Rbrack: 1,
+  Type:   nil,
+  Values: []ast.Expr(nil),
+}
+
+--- SQL
+[]
diff --git a/testdata/result/expr/array_literal_empty_without_types.sql.txt b/testdata/result/expr/array_literal_empty_without_types.sql.txt
new file mode 100644
index 0000000..84ecb55
--- /dev/null
+++ b/testdata/result/expr/array_literal_empty_without_types.sql.txt
@@ -0,0 +1,13 @@
+--- array_literal_empty_without_types.sql
+ARRAY[]
+--- AST
+&ast.ArrayLiteral{
+  Array:  0,
+  Lbrack: 5,
+  Rbrack: 6,
+  Type:   nil,
+  Values: []ast.Expr(nil),
+}
+
+--- SQL
+ARRAY[]
diff --git a/testdata/result/query/select_cast.sql.txt b/testdata/result/query/select_cast.sql.txt
index 24c713e..de64735 100644
--- a/testdata/result/query/select_cast.sql.txt
+++ b/testdata/result/query/select_cast.sql.txt
@@ -69,7 +69,7 @@ limit cast(1 as INT64) offset cast(@foo as INT64)
                 Value:    "1",
               },
               &ast.ArrayLiteral{
-                Array:  0,
+                Array:  -1,
                 Lbrack: 66,
                 Rbrack: 71,
                 Type:   nil,
@@ -89,7 +89,7 @@ limit cast(1 as INT64) offset cast(@foo as INT64)
                 },
               },
               &ast.ArrayLiteral{
-                Array:  0,
+                Array:  -1,
                 Lbrack: 74,
                 Rbrack: 83,
                 Type:   nil,
@@ -297,4 +297,4 @@ limit cast(1 as INT64) offset cast(@foo as INT64)
 }
 
 --- SQL
-SELECT CAST(1 AS INT64), CAST(0.1 AS FLOAT32), CAST(STRUCT(STRUCT(), 1, ARRAY[2, 3], ARRAY["4", "5"]) AS STRUCT<STRUCT<>, x INT64, y ARRAY<INT64>, z ARRAY<STRING>>) FROM x TABLESAMPLE BERNOULLI (CAST(0.1 AS FLOAT64) PERCENT), y TABLESAMPLE BERNOULLI (CAST(1 AS INT64) ROWS), z TABLESAMPLE BERNOULLI (CAST(@param AS INT64) ROWS) LIMIT CAST(1 AS INT64) OFFSET CAST(@foo AS INT64)
+SELECT CAST(1 AS INT64), CAST(0.1 AS FLOAT32), CAST(STRUCT(STRUCT(), 1, [2, 3], ["4", "5"]) AS STRUCT<STRUCT<>, x INT64, y ARRAY<INT64>, z ARRAY<STRING>>) FROM x TABLESAMPLE BERNOULLI (CAST(0.1 AS FLOAT64) PERCENT), y TABLESAMPLE BERNOULLI (CAST(1 AS INT64) ROWS), z TABLESAMPLE BERNOULLI (CAST(@param AS INT64) ROWS) LIMIT CAST(1 AS INT64) OFFSET CAST(@foo AS INT64)
diff --git a/testdata/result/query/select_expr.sql.txt b/testdata/result/query/select_expr.sql.txt
index fd1d0fc..eeb46ce 100644
--- a/testdata/result/query/select_expr.sql.txt
+++ b/testdata/result/query/select_expr.sql.txt
@@ -383,7 +383,7 @@ select 1 + 2, 1 - 2,
           Rbrack:  259,
           Ordinal: false,
           Expr:    &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 240,
             Rbrack: 248,
             Type:   nil,
@@ -421,7 +421,7 @@ select 1 + 2, 1 - 2,
           Rbrack:  290,
           Ordinal: false,
           Expr:    &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 269,
             Rbrack: 277,
             Type:   nil,
@@ -459,7 +459,7 @@ select 1 + 2, 1 - 2,
           Rbrack:  320,
           Ordinal: true,
           Expr:    &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 300,
             Rbrack: 308,
             Type:   nil,
@@ -706,7 +706,7 @@ select 1 + 2, 1 - 2,
             Unnest: 666,
             Rparen: 682,
             Expr:   &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 673,
               Rbrack: 681,
               Type:   nil,
@@ -824,7 +824,7 @@ select 1 + 2, 1 - 2,
         Expr: &ast.BinaryExpr{
           Op:   "||",
           Left: &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 754,
             Rbrack: 756,
             Type:   nil,
@@ -838,7 +838,7 @@ select 1 + 2, 1 - 2,
             },
           },
           Right: &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 761,
             Rbrack: 763,
             Type:   nil,
@@ -928,4 +928,4 @@ select 1 + 2, 1 - 2,
 }
 
 --- SQL
-SELECT 1 + 2, 1 - 2, 1 * 2, 2 / 2, +1 + +1, -1 + -1, +1.2, -3.4, ~1 ^ ~1, 1 ^ 2, 2 & 1, 2 | 1, 1 << 2, 2 >> 1, foo.bar * +foo.bar * -foo.bar, (SELECT 1 AS `1`).`1`, NOT NOT TRUE, ARRAY[1, 2, 3][OFFSET(1)], ARRAY[1, 2, 3][OFFSET(1)], ARRAY[1, 2, 3][ORDINAL(1)], CASE WHEN 1 = 1 THEN "1 = 1" ELSE "else" END, CASE 1 WHEN 1 THEN "1" WHEN 2 THEN "2" ELSE "other" END, date_add(DATE "2019-09-01", INTERVAL 5 day), timestamp_add(TIMESTAMP "2019-09-01 08:11:22", INTERVAL 5 hour), 1 IN (1, 2, 3), 2 IN UNNEST(ARRAY[1, 2, 3]), 3 IN (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3), ARRAY[1] || ARRAY[2], IF(1 > 1, 1, 2) + 1 AS result
+SELECT 1 + 2, 1 - 2, 1 * 2, 2 / 2, +1 + +1, -1 + -1, +1.2, -3.4, ~1 ^ ~1, 1 ^ 2, 2 & 1, 2 | 1, 1 << 2, 2 >> 1, foo.bar * +foo.bar * -foo.bar, (SELECT 1 AS `1`).`1`, NOT NOT TRUE, [1, 2, 3][OFFSET(1)], [1, 2, 3][OFFSET(1)], [1, 2, 3][ORDINAL(1)], CASE WHEN 1 = 1 THEN "1 = 1" ELSE "else" END, CASE 1 WHEN 1 THEN "1" WHEN 2 THEN "2" ELSE "other" END, date_add(DATE "2019-09-01", INTERVAL 5 day), timestamp_add(TIMESTAMP "2019-09-01 08:11:22", INTERVAL 5 hour), 1 IN (1, 2, 3), 2 IN UNNEST([1, 2, 3]), 3 IN (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3), [1] || [2], IF(1 > 1, 1, 2) + 1 AS result
diff --git a/testdata/result/query/select_literals_all.sql.txt b/testdata/result/query/select_literals_all.sql.txt
index c821ffc..b8556bb 100644
--- a/testdata/result/query/select_literals_all.sql.txt
+++ b/testdata/result/query/select_literals_all.sql.txt
@@ -263,7 +263,7 @@ lines''',
       },
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 352,
           Rbrack: 360,
           Type:   nil,
@@ -291,7 +291,7 @@ lines''',
       },
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 365,
           Rbrack: 380,
           Type:   nil,
@@ -631,4 +631,4 @@ lines''',
 }
 
 --- SQL
-SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
+SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
diff --git a/testdata/result/query/select_literals_array.sql.txt b/testdata/result/query/select_literals_array.sql.txt
index 0780c3c..5955dc6 100644
--- a/testdata/result/query/select_literals_array.sql.txt
+++ b/testdata/result/query/select_literals_array.sql.txt
@@ -17,7 +17,7 @@ SELECT
     Results:  []ast.SelectItem{
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 9,
           Rbrack: 17,
           Type:   nil,
@@ -45,7 +45,7 @@ SELECT
       },
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 22,
           Rbrack: 37,
           Type:   nil,
@@ -147,4 +147,4 @@ SELECT
 }
 
 --- SQL
-SELECT ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[]
+SELECT [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[]
diff --git a/testdata/result/query/select_literals_array_invalid.sql.txt b/testdata/result/query/select_literals_array_invalid.sql.txt
index 762f3be..2ffd9a3 100644
--- a/testdata/result/query/select_literals_array_invalid.sql.txt
+++ b/testdata/result/query/select_literals_array_invalid.sql.txt
@@ -13,13 +13,13 @@ SELECT
     Results:  []ast.SelectItem{
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 9,
           Rbrack: 41,
           Type:   nil,
           Values: []ast.Expr{
             &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 10,
               Rbrack: 18,
               Type:   nil,
@@ -45,7 +45,7 @@ SELECT
               },
             },
             &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 21,
               Rbrack: 29,
               Type:   nil,
@@ -71,7 +71,7 @@ SELECT
               },
             },
             &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 32,
               Rbrack: 40,
               Type:   nil,
@@ -110,4 +110,4 @@ SELECT
 }
 
 --- SQL
-SELECT ARRAY[ARRAY[1, 2, 3], ARRAY[2, 4, 6], ARRAY[3, 6, 9]]
+SELECT [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
diff --git a/testdata/result/query/select_unnest_with_offset.sql.txt b/testdata/result/query/select_unnest_with_offset.sql.txt
index db6f9ac..669cd21 100644
--- a/testdata/result/query/select_unnest_with_offset.sql.txt
+++ b/testdata/result/query/select_unnest_with_offset.sql.txt
@@ -24,7 +24,7 @@ FROM
         Rparen:   32,
         Implicit: false,
         Expr:     &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 25,
           Rbrack: 31,
           Type:   nil,
@@ -86,4 +86,4 @@ FROM
 }
 
 --- SQL
-SELECT * FROM UNNEST(ARRAY[1, 2, 3]) @{hint=1} WITH OFFSET
+SELECT * FROM UNNEST([1, 2, 3]) @{hint=1} WITH OFFSET
diff --git a/testdata/result/query/select_unnest_with_offset_and_alias.sql.txt b/testdata/result/query/select_unnest_with_offset_and_alias.sql.txt
index efa0ca9..5815168 100644
--- a/testdata/result/query/select_unnest_with_offset_and_alias.sql.txt
+++ b/testdata/result/query/select_unnest_with_offset_and_alias.sql.txt
@@ -24,7 +24,7 @@ FROM
         Rparen:   32,
         Implicit: false,
         Expr:     &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 25,
           Rbrack: 31,
           Type:   nil,
@@ -82,4 +82,4 @@ FROM
 }
 
 --- SQL
-SELECT * FROM UNNEST(ARRAY[1, 2, 3]) AS value WITH OFFSET AS num
+SELECT * FROM UNNEST([1, 2, 3]) AS value WITH OFFSET AS num
diff --git a/testdata/result/query/select_unnest_with_offset_and_alias_min.sql.txt b/testdata/result/query/select_unnest_with_offset_and_alias_min.sql.txt
index 067154b..fd9b9e4 100644
--- a/testdata/result/query/select_unnest_with_offset_and_alias_min.sql.txt
+++ b/testdata/result/query/select_unnest_with_offset_and_alias_min.sql.txt
@@ -24,7 +24,7 @@ FROM
         Rparen:   32,
         Implicit: false,
         Expr:     &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 25,
           Rbrack: 31,
           Type:   nil,
@@ -82,4 +82,4 @@ FROM
 }
 
 --- SQL
-SELECT * FROM UNNEST(ARRAY[1, 2, 3]) AS value WITH OFFSET AS num
+SELECT * FROM UNNEST([1, 2, 3]) AS value WITH OFFSET AS num
diff --git a/testdata/result/statement/insert_select.sql.txt b/testdata/result/statement/insert_select.sql.txt
index f7da01d..778f124 100644
--- a/testdata/result/statement/insert_select.sql.txt
+++ b/testdata/result/statement/insert_select.sql.txt
@@ -39,7 +39,7 @@ select * from unnest([(1, 2), (3, 4)])
           Rparen:   59,
           Implicit: false,
           Expr:     &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 43,
             Rbrack: 58,
             Type:   nil,
@@ -102,4 +102,4 @@ select * from unnest([(1, 2), (3, 4)])
 }
 
 --- SQL
-INSERT INTO foo (foo, bar) SELECT * FROM UNNEST(ARRAY[STRUCT(1, 2), STRUCT(3, 4)])
+INSERT INTO foo (foo, bar) SELECT * FROM UNNEST([STRUCT(1, 2), STRUCT(3, 4)])
diff --git a/testdata/result/statement/select_cast.sql.txt b/testdata/result/statement/select_cast.sql.txt
index 24c713e..de64735 100644
--- a/testdata/result/statement/select_cast.sql.txt
+++ b/testdata/result/statement/select_cast.sql.txt
@@ -69,7 +69,7 @@ limit cast(1 as INT64) offset cast(@foo as INT64)
                 Value:    "1",
               },
               &ast.ArrayLiteral{
-                Array:  0,
+                Array:  -1,
                 Lbrack: 66,
                 Rbrack: 71,
                 Type:   nil,
@@ -89,7 +89,7 @@ limit cast(1 as INT64) offset cast(@foo as INT64)
                 },
               },
               &ast.ArrayLiteral{
-                Array:  0,
+                Array:  -1,
                 Lbrack: 74,
                 Rbrack: 83,
                 Type:   nil,
@@ -297,4 +297,4 @@ limit cast(1 as INT64) offset cast(@foo as INT64)
 }
 
 --- SQL
-SELECT CAST(1 AS INT64), CAST(0.1 AS FLOAT32), CAST(STRUCT(STRUCT(), 1, ARRAY[2, 3], ARRAY["4", "5"]) AS STRUCT<STRUCT<>, x INT64, y ARRAY<INT64>, z ARRAY<STRING>>) FROM x TABLESAMPLE BERNOULLI (CAST(0.1 AS FLOAT64) PERCENT), y TABLESAMPLE BERNOULLI (CAST(1 AS INT64) ROWS), z TABLESAMPLE BERNOULLI (CAST(@param AS INT64) ROWS) LIMIT CAST(1 AS INT64) OFFSET CAST(@foo AS INT64)
+SELECT CAST(1 AS INT64), CAST(0.1 AS FLOAT32), CAST(STRUCT(STRUCT(), 1, [2, 3], ["4", "5"]) AS STRUCT<STRUCT<>, x INT64, y ARRAY<INT64>, z ARRAY<STRING>>) FROM x TABLESAMPLE BERNOULLI (CAST(0.1 AS FLOAT64) PERCENT), y TABLESAMPLE BERNOULLI (CAST(1 AS INT64) ROWS), z TABLESAMPLE BERNOULLI (CAST(@param AS INT64) ROWS) LIMIT CAST(1 AS INT64) OFFSET CAST(@foo AS INT64)
diff --git a/testdata/result/statement/select_expr.sql.txt b/testdata/result/statement/select_expr.sql.txt
index fd1d0fc..eeb46ce 100644
--- a/testdata/result/statement/select_expr.sql.txt
+++ b/testdata/result/statement/select_expr.sql.txt
@@ -383,7 +383,7 @@ select 1 + 2, 1 - 2,
           Rbrack:  259,
           Ordinal: false,
           Expr:    &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 240,
             Rbrack: 248,
             Type:   nil,
@@ -421,7 +421,7 @@ select 1 + 2, 1 - 2,
           Rbrack:  290,
           Ordinal: false,
           Expr:    &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 269,
             Rbrack: 277,
             Type:   nil,
@@ -459,7 +459,7 @@ select 1 + 2, 1 - 2,
           Rbrack:  320,
           Ordinal: true,
           Expr:    &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 300,
             Rbrack: 308,
             Type:   nil,
@@ -706,7 +706,7 @@ select 1 + 2, 1 - 2,
             Unnest: 666,
             Rparen: 682,
             Expr:   &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 673,
               Rbrack: 681,
               Type:   nil,
@@ -824,7 +824,7 @@ select 1 + 2, 1 - 2,
         Expr: &ast.BinaryExpr{
           Op:   "||",
           Left: &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 754,
             Rbrack: 756,
             Type:   nil,
@@ -838,7 +838,7 @@ select 1 + 2, 1 - 2,
             },
           },
           Right: &ast.ArrayLiteral{
-            Array:  0,
+            Array:  -1,
             Lbrack: 761,
             Rbrack: 763,
             Type:   nil,
@@ -928,4 +928,4 @@ select 1 + 2, 1 - 2,
 }
 
 --- SQL
-SELECT 1 + 2, 1 - 2, 1 * 2, 2 / 2, +1 + +1, -1 + -1, +1.2, -3.4, ~1 ^ ~1, 1 ^ 2, 2 & 1, 2 | 1, 1 << 2, 2 >> 1, foo.bar * +foo.bar * -foo.bar, (SELECT 1 AS `1`).`1`, NOT NOT TRUE, ARRAY[1, 2, 3][OFFSET(1)], ARRAY[1, 2, 3][OFFSET(1)], ARRAY[1, 2, 3][ORDINAL(1)], CASE WHEN 1 = 1 THEN "1 = 1" ELSE "else" END, CASE 1 WHEN 1 THEN "1" WHEN 2 THEN "2" ELSE "other" END, date_add(DATE "2019-09-01", INTERVAL 5 day), timestamp_add(TIMESTAMP "2019-09-01 08:11:22", INTERVAL 5 hour), 1 IN (1, 2, 3), 2 IN UNNEST(ARRAY[1, 2, 3]), 3 IN (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3), ARRAY[1] || ARRAY[2], IF(1 > 1, 1, 2) + 1 AS result
+SELECT 1 + 2, 1 - 2, 1 * 2, 2 / 2, +1 + +1, -1 + -1, +1.2, -3.4, ~1 ^ ~1, 1 ^ 2, 2 & 1, 2 | 1, 1 << 2, 2 >> 1, foo.bar * +foo.bar * -foo.bar, (SELECT 1 AS `1`).`1`, NOT NOT TRUE, [1, 2, 3][OFFSET(1)], [1, 2, 3][OFFSET(1)], [1, 2, 3][ORDINAL(1)], CASE WHEN 1 = 1 THEN "1 = 1" ELSE "else" END, CASE 1 WHEN 1 THEN "1" WHEN 2 THEN "2" ELSE "other" END, date_add(DATE "2019-09-01", INTERVAL 5 day), timestamp_add(TIMESTAMP "2019-09-01 08:11:22", INTERVAL 5 hour), 1 IN (1, 2, 3), 2 IN UNNEST([1, 2, 3]), 3 IN (SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3), [1] || [2], IF(1 > 1, 1, 2) + 1 AS result
diff --git a/testdata/result/statement/select_literals_all.sql.txt b/testdata/result/statement/select_literals_all.sql.txt
index c821ffc..b8556bb 100644
--- a/testdata/result/statement/select_literals_all.sql.txt
+++ b/testdata/result/statement/select_literals_all.sql.txt
@@ -263,7 +263,7 @@ lines''',
       },
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 352,
           Rbrack: 360,
           Type:   nil,
@@ -291,7 +291,7 @@ lines''',
       },
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 365,
           Rbrack: 380,
           Type:   nil,
@@ -631,4 +631,4 @@ lines''',
 }
 
 --- SQL
-SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
+SELECT "abc", "it\'s", "it\'s", "Title: \"Boy\"", "abc", "it\'s", "Title:\"Boy\"", "two\nlines", "why\?", "abc+", "abc+", "abc+", "f\\(abc,(.*),def\\)", B"abc", B"abc", B"abc", B"abc+", B"abc+", B"abc", 123, 0xABC, -123, -0xABC, 123.456e-67, .1E4, 58., 4e2, [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[], ARRAY(SELECT STRUCT(1, 2, 3)), ARRAY(SELECT STRUCT(1, 2, 3)), DATE "2014-09-27", DATE("2014-09-27"), TIMESTAMP "2014-09-27 12:30:00.45-08", TIMESTAMP "2014-09-27 12:30:00.45 America/Los_Angeles", TIMESTAMP "2014-09-27", TIMESTAMP("2014-09-27"), JSON "1", JSON "[1, 2]", JSON "{}", NUMERIC "0", NUMERIC "0", TRUE, FALSE
diff --git a/testdata/result/statement/select_literals_array.sql.txt b/testdata/result/statement/select_literals_array.sql.txt
index 0780c3c..5955dc6 100644
--- a/testdata/result/statement/select_literals_array.sql.txt
+++ b/testdata/result/statement/select_literals_array.sql.txt
@@ -17,7 +17,7 @@ SELECT
     Results:  []ast.SelectItem{
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 9,
           Rbrack: 17,
           Type:   nil,
@@ -45,7 +45,7 @@ SELECT
       },
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 22,
           Rbrack: 37,
           Type:   nil,
@@ -147,4 +147,4 @@ SELECT
 }
 
 --- SQL
-SELECT ARRAY[1, 2, 3], ARRAY["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[]
+SELECT [1, 2, 3], ["x", "y", "xy"], ARRAY[1, 2, 3], ARRAY<STRING>["x", "y", "xy"], ARRAY<INT64>[]
diff --git a/testdata/result/statement/select_literals_array_invalid.sql.txt b/testdata/result/statement/select_literals_array_invalid.sql.txt
index 762f3be..2ffd9a3 100644
--- a/testdata/result/statement/select_literals_array_invalid.sql.txt
+++ b/testdata/result/statement/select_literals_array_invalid.sql.txt
@@ -13,13 +13,13 @@ SELECT
     Results:  []ast.SelectItem{
       &ast.ExprSelectItem{
         Expr: &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 9,
           Rbrack: 41,
           Type:   nil,
           Values: []ast.Expr{
             &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 10,
               Rbrack: 18,
               Type:   nil,
@@ -45,7 +45,7 @@ SELECT
               },
             },
             &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 21,
               Rbrack: 29,
               Type:   nil,
@@ -71,7 +71,7 @@ SELECT
               },
             },
             &ast.ArrayLiteral{
-              Array:  0,
+              Array:  -1,
               Lbrack: 32,
               Rbrack: 40,
               Type:   nil,
@@ -110,4 +110,4 @@ SELECT
 }
 
 --- SQL
-SELECT ARRAY[ARRAY[1, 2, 3], ARRAY[2, 4, 6], ARRAY[3, 6, 9]]
+SELECT [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
diff --git a/testdata/result/statement/select_unnest_with_offset.sql.txt b/testdata/result/statement/select_unnest_with_offset.sql.txt
index db6f9ac..669cd21 100644
--- a/testdata/result/statement/select_unnest_with_offset.sql.txt
+++ b/testdata/result/statement/select_unnest_with_offset.sql.txt
@@ -24,7 +24,7 @@ FROM
         Rparen:   32,
         Implicit: false,
         Expr:     &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 25,
           Rbrack: 31,
           Type:   nil,
@@ -86,4 +86,4 @@ FROM
 }
 
 --- SQL
-SELECT * FROM UNNEST(ARRAY[1, 2, 3]) @{hint=1} WITH OFFSET
+SELECT * FROM UNNEST([1, 2, 3]) @{hint=1} WITH OFFSET
diff --git a/testdata/result/statement/select_unnest_with_offset_and_alias.sql.txt b/testdata/result/statement/select_unnest_with_offset_and_alias.sql.txt
index efa0ca9..5815168 100644
--- a/testdata/result/statement/select_unnest_with_offset_and_alias.sql.txt
+++ b/testdata/result/statement/select_unnest_with_offset_and_alias.sql.txt
@@ -24,7 +24,7 @@ FROM
         Rparen:   32,
         Implicit: false,
         Expr:     &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 25,
           Rbrack: 31,
           Type:   nil,
@@ -82,4 +82,4 @@ FROM
 }
 
 --- SQL
-SELECT * FROM UNNEST(ARRAY[1, 2, 3]) AS value WITH OFFSET AS num
+SELECT * FROM UNNEST([1, 2, 3]) AS value WITH OFFSET AS num
diff --git a/testdata/result/statement/select_unnest_with_offset_and_alias_min.sql.txt b/testdata/result/statement/select_unnest_with_offset_and_alias_min.sql.txt
index 067154b..fd9b9e4 100644
--- a/testdata/result/statement/select_unnest_with_offset_and_alias_min.sql.txt
+++ b/testdata/result/statement/select_unnest_with_offset_and_alias_min.sql.txt
@@ -24,7 +24,7 @@ FROM
         Rparen:   32,
         Implicit: false,
         Expr:     &ast.ArrayLiteral{
-          Array:  0,
+          Array:  -1,
           Lbrack: 25,
           Rbrack: 31,
           Type:   nil,
@@ -82,4 +82,4 @@ FROM
 }
 
 --- SQL
-SELECT * FROM UNNEST(ARRAY[1, 2, 3]) AS value WITH OFFSET AS num
+SELECT * FROM UNNEST([1, 2, 3]) AS value WITH OFFSET AS num