Skip to content

Commit d13ed61

Browse files
authored
Add sql-compatibility parsing of arrays in parens if at least 2 elements. (#115)
1 parent 2daeb7a commit d13ed61

File tree

2 files changed

+40
-12
lines changed

2 files changed

+40
-12
lines changed

partiql-parser/src/parse/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,9 @@ mod tests {
242242
fn array() {
243243
value_and_parse!(r#"[]"#);
244244
value_and_parse!(r#"[1, 'moo', "some variable", [], 'a', MISSING]"#);
245+
// In the interest of compatibility to SQL, PartiQL also allows array constructors to be
246+
// denoted with parentheses instead of brackets, when there are at least two elements in the array
247+
value_and_parse!(r#"(1, 'moo', "some variable", [], 'a', MISSING)"#);
245248
}
246249
#[test]
247250
fn bag() {

partiql-parser/src/parse/partiql.lalrpop

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ WithClause: () = {}
9494
// ------------------------------------------------------------------------------ //
9595
SelectClause: ast::Projection = {
9696
"SELECT" "*" => ast::Projection::ProjectStar,
97-
"SELECT" <project_items:CommaSep<Projection>> => ast::Projection::ProjectList(project_items),
97+
"SELECT" <project_items:CommaSepPlus<Projection>> => ast::Projection::ProjectList(project_items),
9898
"SELECT" "VALUE" <value:ExprQuery> => ast::Projection::ProjectValue(value),
9999
"PIVOT" <value:ExprQuery> "AT" <key:ExprQuery> => {
100100
ast::Projection::ProjectPivot { key, value }
@@ -235,7 +235,7 @@ JoinType: ast::JoinKind = {
235235
#[inline]
236236
JoinSpec: ast::JoinSpec = {
237237
"ON" <e:ExprQuery> => ast::JoinSpec::On(e),
238-
"USING" "(" <paths:CommaSep<PathExpr>> ")" => ast::JoinSpec::Using( paths ),
238+
"USING" "(" <paths:CommaSepPlus<PathExpr>> ")" => ast::JoinSpec::Using( paths ),
239239
}
240240

241241
// ------------------------------------------------------------------------------ //
@@ -247,7 +247,7 @@ WhereClause: Box<ast::Expr> = { "WHERE" <ExprQuery> }
247247
// GROUP BY //
248248
// ------------------------------------------------------------------------------ //
249249
GroupClause: Box<ast::GroupByExpr> = {
250-
"GROUP" <strategy: GroupStrategy> "BY" <keys:CommaSep<GroupKey>> <group_as_alias:GroupAlias?> => {
250+
"GROUP" <strategy: GroupStrategy> "BY" <keys:CommaSepPlus<GroupKey>> <group_as_alias:GroupAlias?> => {
251251
Box::new(ast::GroupByExpr{
252252
strategy,
253253
key_list: ast::GroupKeyList{ keys },
@@ -293,7 +293,7 @@ SetOpClause: () = {}
293293
// ------------------------------------------------------------------------------ //
294294
OrderByClause: Box<ast::OrderByExpr> = {
295295
"ORDER" "BY" "PRESERVE" => Box::new( ast::OrderByExpr{ sort_specs: vec![] } ),
296-
"ORDER" "BY" <sort_specs: CommaSep<OrderSortSpec>> => Box::new( ast::OrderByExpr{ sort_specs } ),
296+
"ORDER" "BY" <sort_specs: CommaSepPlus<OrderSortSpec>> => Box::new( ast::OrderByExpr{ sort_specs } ),
297297
}
298298
#[inline]
299299
OrderSortSpec: ast::SortSpec = {
@@ -647,9 +647,10 @@ pub ExprTerm: ast::Expr = {
647647
"(" <q:Query> ")" => *q,
648648
<lo:@L> <lit:Literal> <hi:@R> => ast::Expr{ kind: ast::ExprKind::Lit( lit.ast(lo..hi) ) },
649649
<lo:@L> <path:PathExpr> <hi:@R> => ast::Expr{ kind: ast::ExprKind::Path( path.ast(lo..hi) ) },
650-
<lo:@L> "{" <fields:CommaTerm<ExprPair>> "}" <hi:@R> => ast::Expr{ kind: ast::ExprKind::Struct( ast::Struct{fields}.ast(lo..hi) ) },
651-
<lo:@L> "[" <values:CommaTerm<ExprQuery>> "]" <hi:@R> => ast::Expr{ kind: ast::ExprKind::List( ast::List{values}.ast(lo..hi) ) },
652-
<lo:@L> "<<" <values:CommaTerm<ExprQuery>> ">>" <hi:@R> => ast::Expr{ kind: ast::ExprKind::Bag( ast::Bag{values}.ast(lo..hi) ) },
650+
<lo:@L> "{" <fields:CommaTermStar<ExprPair>> "}" <hi:@R> => ast::Expr{ kind: ast::ExprKind::Struct( ast::Struct{fields}.ast(lo..hi) ) },
651+
<lo:@L> "[" <values:CommaTermStar<ExprQuery>> "]" <hi:@R> => ast::Expr{ kind: ast::ExprKind::List( ast::List{values}.ast(lo..hi) ) },
652+
<lo:@L> "(" <values:CommaTermPlus<ExprQuery>> ")" <hi:@R> => ast::Expr{ kind: ast::ExprKind::List( ast::List{values}.ast(lo..hi) ) },
653+
<lo:@L> "<<" <values:CommaTermStar<ExprQuery>> ">>" <hi:@R> => ast::Expr{ kind: ast::ExprKind::Bag( ast::Bag{values}.ast(lo..hi) ) },
653654
! => { errors.push(<>); ast::Expr{ kind: ast::ExprKind::Error} },
654655
}
655656

@@ -659,7 +660,7 @@ ExprPair: ast::ExprPair = {
659660

660661
#[inline]
661662
FunctionCall: ast::Call = {
662-
<func_name:"Identifier"> "(" <args:CommaSep<ExprQuery>> ")" =>
663+
<func_name:"Identifier"> "(" <args:CommaSepPlus<ExprQuery>> ")" =>
663664
ast::Call{ func_name: ast::SymbolPrimitive{ value: func_name.to_owned() }, args }
664665
}
665666

@@ -778,9 +779,9 @@ LiteralIon: ast::Lit = {
778779
// //
779780
// ------------------------------------------------------------------------------ //
780781

781-
// Comma as terminator (i.e. "<T>, <T>, <T>," where final comma is optional)
782+
// Comma as terminator (i.e. "<T>, <T>, <T>," where final comma is optional); may be empty
782783
// This is a macro; see http://lalrpop.github.io/lalrpop/tutorial/006_macros.html
783-
CommaTerm<T>: Vec<T> = {
784+
CommaTermStar<T>: Vec<T> = {
784785
<mut v:(<T> ",")*> <e:T?> => match e {
785786
None => v,
786787
Some(e) => {
@@ -790,9 +791,33 @@ CommaTerm<T>: Vec<T> = {
790791
}
791792
};
792793

793-
// Comma as separator (i.e. "<T>, <T>, <T>")
794+
// Comma as terminator (i.e. "<T>, <T>, <T>," where final comma is optional); at least 1 arg
794795
// This is a macro; see http://lalrpop.github.io/lalrpop/tutorial/006_macros.html
795-
CommaSep<T>: Vec<T> = {
796+
CommaTermPlus<T>: Vec<T> = {
797+
<mut v:(<T> ",")+> <e:T?> => match e {
798+
None => v,
799+
Some(e) => {
800+
v.push(e);
801+
v
802+
}
803+
}
804+
};
805+
806+
// Comma as separator (i.e. "<T>, <T>, <T>"); may be empty
807+
// This is a macro; see http://lalrpop.github.io/lalrpop/tutorial/006_macros.html
808+
CommaSepStar<T>: Vec<T> = {
809+
<e:T?> <mut v:("," <T>)*> => match e {
810+
None => vec![],
811+
Some(e) => {
812+
v.insert(0,e);
813+
v
814+
}
815+
}
816+
};
817+
818+
// Comma as separator (i.e. "<T>, <T>, <T>"); at least 1 arg
819+
// This is a macro; see http://lalrpop.github.io/lalrpop/tutorial/006_macros.html
820+
CommaSepPlus<T>: Vec<T> = {
796821
<mut v:(<T> ",")*> <e:T> => {
797822
v.push(e);
798823
v

0 commit comments

Comments
 (0)