@@ -94,7 +94,7 @@ WithClause: () = {}
94
94
// ------------------------------------------------------------------------------ //
95
95
SelectClause: ast::Projection = {
96
96
"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),
98
98
"SELECT" "VALUE" <value:ExprQuery> => ast::Projection::ProjectValue(value),
99
99
"PIVOT" <value:ExprQuery> "AT" <key:ExprQuery> => {
100
100
ast::Projection::ProjectPivot { key, value }
@@ -235,7 +235,7 @@ JoinType: ast::JoinKind = {
235
235
#[inline]
236
236
JoinSpec: ast::JoinSpec = {
237
237
"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 ),
239
239
}
240
240
241
241
// ------------------------------------------------------------------------------ //
@@ -247,7 +247,7 @@ WhereClause: Box<ast::Expr> = { "WHERE" <ExprQuery> }
247
247
// GROUP BY //
248
248
// ------------------------------------------------------------------------------ //
249
249
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?> => {
251
251
Box::new(ast::GroupByExpr{
252
252
strategy,
253
253
key_list: ast::GroupKeyList{ keys },
@@ -293,7 +293,7 @@ SetOpClause: () = {}
293
293
// ------------------------------------------------------------------------------ //
294
294
OrderByClause: Box<ast::OrderByExpr> = {
295
295
"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 } ),
297
297
}
298
298
#[inline]
299
299
OrderSortSpec: ast::SortSpec = {
@@ -647,9 +647,10 @@ pub ExprTerm: ast::Expr = {
647
647
"(" <q:Query> ")" => *q,
648
648
<lo:@L> <lit:Literal> <hi:@R> => ast::Expr{ kind: ast::ExprKind::Lit( lit.ast(lo..hi) ) },
649
649
<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) ) },
653
654
! => { errors.push(<>); ast::Expr{ kind: ast::ExprKind::Error} },
654
655
}
655
656
@@ -659,7 +660,7 @@ ExprPair: ast::ExprPair = {
659
660
660
661
#[inline]
661
662
FunctionCall: ast::Call = {
662
- <func_name:"Identifier"> "(" <args:CommaSep <ExprQuery>> ")" =>
663
+ <func_name:"Identifier"> "(" <args:CommaSepPlus <ExprQuery>> ")" =>
663
664
ast::Call{ func_name: ast::SymbolPrimitive{ value: func_name.to_owned() }, args }
664
665
}
665
666
@@ -778,9 +779,9 @@ LiteralIon: ast::Lit = {
778
779
// //
779
780
// ------------------------------------------------------------------------------ //
780
781
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
782
783
// This is a macro; see http://lalrpop.github.io/lalrpop/tutorial/006_macros.html
783
- CommaTerm <T>: Vec<T> = {
784
+ CommaTermStar <T>: Vec<T> = {
784
785
<mut v:(<T> ",")*> <e:T?> => match e {
785
786
None => v,
786
787
Some(e) => {
@@ -790,9 +791,33 @@ CommaTerm<T>: Vec<T> = {
790
791
}
791
792
};
792
793
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
794
795
// 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> = {
796
821
<mut v:(<T> ",")*> <e:T> => {
797
822
v.push(e);
798
823
v
0 commit comments