+
+// LINQ
+
+query_expression
+ : from_clause query_body
+ {
+ lexer.QueryParsing = false;
+ $$ = new Linq.QueryExpression (current_container, current_block, (Expression)$1, (Linq.AQueryClause)$2);
+ end_block (lexer.Location);
+ }
+ ;
+
+from_clause
+ : FROM IDENTIFIER IN expression opt_join_clauses
+ {
+ start_block (lexer.Location);
+ LocatedToken lt = (LocatedToken) $2;
+
+ LocalInfo vi = current_block.AddVariable (TypeManager.system_object_expr, lt.Value, lt.Location); // TODO: null is var type
+ if (vi != null) {
+ $$ = new LocalVariableReference (current_block, lt.Value, lt.Location, vi, false);
+ }
+ $$ = $4;
+ }
+ | FROM type IDENTIFIER IN expression opt_join_clauses
+ {
+ start_block (lexer.Location);
+ LocatedToken lt = (LocatedToken) $3;
+
+ Expression type = (Expression)$2;
+ LocalInfo vi = current_block.AddVariable (type, lt.Value, lt.Location);
+ $$ = new Linq.Cast (type, (Expression)$5, lt.Location);
+ }
+ ;
+
+opt_join_clauses
+ : /* empty */
+ | join_clauses
+ ;
+
+join_clauses
+ : join_clause
+ | join_clauses join_clause
+ ;
+
+join_clause
+ : JOIN join_clause_body
+ | JOIN join_clause_body INTO IDENTIFIER
+ | JOIN type join_clause_body
+ | JOIN type join_clause_body INTO IDENTIFIER
+ ;
+
+join_clause_body
+ : IDENTIFIER IN expression ON expression EQUALS expression
+ ;
+
+query_body
+ : opt_from_let_where_clauses opt_orderby_clause SELECT expression opt_query_continuation
+ {
+ Linq.AQueryClause ret = new Linq.Select ((Expression)$4, GetLocation ($3));
+
+ if ($1 != null) {
+ ((Linq.AQueryClause)$1).Next = ret;
+ ret = (Linq.AQueryClause)$1;
+ }
+
+ $$ = ret;
+ }
+ | opt_from_let_where_clauses opt_orderby_clause group_clause opt_query_continuation
+ ;
+
+opt_from_let_where_clauses
+ : /* empty */
+ | from_let_where_clauses
+ ;
+
+from_let_where_clauses
+ : from_let_where_clause
+ | from_let_where_clauses from_let_where_clause
+ ;
+
+from_let_where_clause
+ : from_clause
+ | let_clause
+ | where_clause
+ ;
+
+let_clause
+ : LET IDENTIFIER ASSIGN expression
+ ;
+
+where_clause
+ : WHERE boolean_expression
+ {
+ $$ = new Linq.Where ((Expression)$2, GetLocation ($1));
+ }
+ ;
+
+opt_orderby_clause
+ : /* empty */
+ | orderby_clause
+ ;
+
+orderby_clause
+ : ORDERBY orderings
+ ;
+
+orderings
+ : ordering
+ | orderings COMMA ordering
+ ;
+
+ordering
+ : expression
+ | expression ASCENDING
+ | expression DESCENDING
+ ;
+
+
+group_clause
+ : GROUP expression BY expression
+ ;
+
+opt_query_continuation
+ : /* empty */
+ | query_continuation
+ ;
+
+query_continuation
+ : INTO IDENTIFIER opt_join_clauses query_body
+ ;
+