Carlos Manuel Lopez has proposed merging lp:~zorba-coders/zorba/new-groupby 
into lp:zorba.

Requested reviews:
  Zorba Coders (zorba-coders)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/new-groupby/+merge/108231

Implements new group by syntax, as defined in the XQuery 3.0 Spec since 
September 2011

The group by is converted into the syntactically equivalent combination of lets 
and a group by as defined by the spec.
-- 
https://code.launchpad.net/~zorba-coders/zorba/new-groupby/+merge/108231
Your team Zorba Coders is requested to review the proposed merge of 
lp:~zorba-coders/zorba/new-groupby into lp:zorba.
=== modified file 'src/compiler/parser/xquery_parser.y'
--- src/compiler/parser/xquery_parser.y	2012-05-16 17:25:48 +0000
+++ src/compiler/parser/xquery_parser.y	2012-05-31 20:11:22 +0000
@@ -2924,12 +2924,42 @@
 GroupSpec :
     DOLLAR QNAME
     {
-      $$ = new GroupSpec(LOC(@$), static_cast<QName*>($2), NULL);
+      $$ = new GroupSpec(LOC(@$), static_cast<QName*>($2), NULL, NULL, NULL);
+    }
+  | DOLLAR QNAME GETS ExprSingle
+    {
+      $$ = new GroupSpec(LOC(@$), static_cast<QName*>($2), NULL, $4, NULL);
+    }
+  | DOLLAR QNAME TypeDeclaration GETS ExprSingle
+    {
+      $$ = new GroupSpec(LOC(@$),
+                         static_cast<QName*>($2),
+                         dynamic_cast<SequenceType*>($3),
+                         $5,
+                         NULL);
+    }
+  | DOLLAR QNAME TypeDeclaration GETS ExprSingle GroupCollationSpec
+    {
+      $$ = new GroupSpec(LOC(@$),
+                         static_cast<QName*>($2),
+                         dynamic_cast<SequenceType*>($3),
+                         $5,
+                         dynamic_cast<GroupCollationSpec*>($6));
+    }
+  | DOLLAR QNAME GETS ExprSingle GroupCollationSpec
+    {
+      $$ = new GroupSpec(LOC(@$),
+                         static_cast<QName*>($2),
+                         NULL,
+                         $4,
+                         dynamic_cast<GroupCollationSpec*>($5));
     }
   | DOLLAR QNAME GroupCollationSpec
     {
       $$ = new GroupSpec(LOC(@$),
                          static_cast<QName*>($2),
+                         NULL,
+                         NULL,
                          dynamic_cast<GroupCollationSpec*>($3));
     }
   ;

=== modified file 'src/compiler/parsetree/parsenodes.cpp'
--- src/compiler/parsetree/parsenodes.cpp	2012-05-03 12:31:51 +0000
+++ src/compiler/parsetree/parsenodes.cpp	2012-05-31 20:11:22 +0000
@@ -1774,16 +1774,28 @@
   vector<rchandle<GroupSpec> >::const_iterator ite = theSpecs.begin();
   vector<rchandle<GroupSpec> >::const_iterator end = theSpecs.end();
 
-  for (; ite != end; ++ite)
+  //If no expression is given, then it'll just be the variable.
+  //If this is the case, and the variable is already defined as a
+  //grouping variable, it makes no sense to add it, so this is a
+  //quick optimization.
+  if(spec->get_var_expr() == NULL)
   {
-    const GroupSpec* currSpec = (*ite).getp();
-
-    if (*currSpec->get_var_name() == *spec->get_var_name())
-      break;
+    for (; ite != end; ++ite)
+    {
+      const GroupSpec* currSpec = (*ite).getp();
+
+      if (*currSpec->get_var_name() == *spec->get_var_name() &&
+          currSpec->get_var_expr() == NULL)
+        break;
+    }
+
+    if (ite == end)
+      theSpecs.push_back(spec);
   }
-
-  if (ite == end)
+  else
+  {
     theSpecs.push_back(spec);
+  }
 }
 
 
@@ -1805,10 +1817,14 @@
 GroupSpec::GroupSpec(
   const QueryLoc& loc_,
   rchandle<QName> _var_name_h,
+  rchandle<SequenceType> _var_type_h,
+  rchandle<exprnode> _var_value_h,
   rchandle<GroupCollationSpec> _group_coll_spec_h)
   :
   parsenode(loc_),
   var_name_h(_var_name_h),
+  var_type_h(_var_type_h),
+  var_init_expr_h(_var_value_h),
   group_coll_spec_h(_group_coll_spec_h)
 {
 }
@@ -1817,7 +1833,9 @@
 void GroupSpec::accept(parsenode_visitor& v) const
 {
   BEGIN_VISITOR();
+  ACCEPT (var_type_h);
   ACCEPT (group_coll_spec_h);
+  ACCEPT (var_init_expr_h);
   END_VISITOR();
 }
 

=== modified file 'src/compiler/parsetree/parsenodes.h'
--- src/compiler/parsetree/parsenodes.h	2012-05-16 17:16:44 +0000
+++ src/compiler/parsetree/parsenodes.h	2012-05-31 20:11:22 +0000
@@ -2207,22 +2207,30 @@
 
 
 /*******************************************************************************
-  GroupSpec ::= "$" VarName ("collation" URILiteral)?
+  GroupSpec ::= "$" VarName (TypeDeclaration? ":=" ExprSingle)? ("collation" URILiteral)?
 ********************************************************************************/
 class GroupSpec : public parsenode
 {
 protected:
   rchandle<QName>              var_name_h;
   rchandle<GroupCollationSpec> group_coll_spec_h;
+  rchandle<exprnode>           var_init_expr_h;
+  rchandle<SequenceType>       var_type_h;
 
 public:
   GroupSpec(
     const QueryLoc&,
     rchandle<QName>,
+    rchandle<SequenceType>,
+    rchandle<exprnode>,
     rchandle<GroupCollationSpec>);
 
   const QName* get_var_name() const { return var_name_h.getp(); }
 
+  const rchandle<exprnode> get_var_expr() const {return var_init_expr_h;}
+
+  const rchandle<SequenceType> get_var_type() const {return var_type_h;}
+
   rchandle<GroupCollationSpec> group_coll_spec() const { return group_coll_spec_h; }
 
   void accept(parsenode_visitor&) const;
@@ -3106,7 +3114,7 @@
   protected:
     rchandle<exprnode> left;
     rchandle<exprnode> right;
-  
+
   public:
     StringConcatExpr(
       const QueryLoc& aLoc,

=== modified file 'src/compiler/translator/translator.cpp'
--- src/compiler/translator/translator.cpp	2012-05-09 23:06:41 +0000
+++ src/compiler/translator/translator.cpp	2012-05-31 20:11:22 +0000
@@ -717,7 +717,7 @@
 }
 
 
-~TranslatorImpl() 
+~TranslatorImpl()
 {
 #ifndef ZORBA_NO_FULL_TEXT
   while (!theFTNodeStack.empty())
@@ -1223,7 +1223,7 @@
   method raises error.
 
   If var is not found, the method raises the given error, unless the given error
-  is MAX_ZORBA_ERROR_CODE, in which case it returns NULL.
+  is zerr::ZXQP0000_NO_ERROR, in which case it returns NULL.
 ********************************************************************************/
 var_expr* lookup_var(
     const QName* qname,
@@ -1780,7 +1780,7 @@
 
     if (typeid(c) == typeid(ForClause))
     {
-      const VarInDeclList& varDecls = 
+      const VarInDeclList& varDecls =
       *(static_cast<const ForClause*>(&c)->get_vardecl_list());
 
       for (int j =  (int)varDecls.size() - 1; j >= 0; --j)
@@ -1795,7 +1795,7 @@
     }
     else if (typeid(c) == typeid(LetClause))
     {
-      const VarGetsDeclList& lV = 
+      const VarGetsDeclList& lV =
       *(static_cast<const LetClause*>(&c)->get_vardecl_list());
 
       for (int j =  (int)lV.size() - 1; j >= 0; --j)
@@ -1839,6 +1839,16 @@
     }
     else if (typeid (c) == typeid (GroupByClause))
     {
+      const GroupByClause groupClause = *static_cast<const GroupByClause*>(&c);
+
+      //Group-by clauses may define new variables, otherwise it shadows existing vars.
+      for(size_t gSpecPos = 0; gSpecPos < groupClause.get_spec_list()->size(); gSpecPos++)
+      {
+        GroupSpec *groupSpec = (*(groupClause.get_spec_list()))[gSpecPos];
+        if(groupSpec->get_var_expr() != NULL)
+          vars.insert(lookup_var(groupSpec->get_var_name(), loc, err::XPST0008));
+      }
+
       // Group-by redefines ALL previous variables, but the GroupByClause lists
       // only the grouping vars. So, to find the var_exprs for the vars defined
       // by the GroupByClause, we exploit the fact that the redefined var_exprs
@@ -2285,7 +2295,7 @@
 
   // If an appliaction set a type for the context item via the c++ api, then
   // create a full declaration for it in order to enforce that type.
-  if (!theHaveContextItemDecl && 
+  if (!theHaveContextItemDecl &&
       theSctx->get_context_item_type() != theRTM.ITEM_TYPE_ONE.getp())
   {
     var_expr* var = lookup_ctx_var(DOT_VARNAME, loc);
@@ -3310,6 +3320,44 @@
                                     qnameItem->getLocalName())));
         }
 
+<<<<<<< TREE
+=======
+#ifndef ZORBA_NO_FULL_TEXT
+        if (qnameItem->getNamespace() == static_context::ZORBA_FULL_TEXT_FN_NS &&
+            (qnameItem->getLocalName() == "tokenizer-properties" ||
+             qnameItem->getLocalName() == "tokenize"))
+        {
+          FunctionConsts::FunctionKind kind;
+
+          if (qnameItem->getLocalName() == "tokenizer-properties")
+          {
+            assert(numParams <= 1);
+
+            if (numParams == 1)
+              kind = FunctionConsts::FULL_TEXT_TOKENIZER_PROPERTIES_1;
+            else
+              kind = FunctionConsts::FULL_TEXT_TOKENIZER_PROPERTIES_0;
+
+            f = new full_text_tokenizer_properties(f->getSignature(), kind);
+          }
+          else
+          {
+            assert(numParams == 1 || numParams == 2);
+
+            if (numParams == 2)
+              kind = FunctionConsts::FULL_TEXT_TOKENIZE_2;
+            else
+              kind = FunctionConsts::FULL_TEXT_TOKENIZE_1;
+
+            f = new full_text_tokenize(f->getSignature(), kind);
+          }
+
+          f->setStaticContext(theRootSctx);
+          bind_fn(f, numParams, loc);
+        }
+#endif /* ZORBA_NO_FULL_TEXT */
+
+>>>>>>> MERGE-SOURCE
         f->setAnnotations(theAnnotations);
         theAnnotations = NULL; // important to reset
 
@@ -3625,7 +3673,7 @@
   {
     //lc->setLazyEval(!f->isSequential());
 
-    const user_function* udf = 
+    const user_function* udf =
     static_cast<const user_function*>(theCurrentPrologVFDecl.getFunction());
 
     arg_var->set_param_pos(flwor->num_clauses());
@@ -3795,7 +3843,7 @@
       bind_var(ve, export_sctx);
 
 #ifdef ZORBA_WITH_DEBUGGER
-    if (initExpr != NULL && theCCB->theDebuggerCommons != NULL) 
+    if (initExpr != NULL && theCCB->theDebuggerCommons != NULL)
     {
       QueryLoc lExpandedLocation = expandQueryLoc(v.get_name()->get_location(),
                                                   initExpr->get_loc());
@@ -6047,30 +6095,22 @@
   return no_state;
 }
 
-void end_visit(const VarGetsDecl& v, void* /*visit_state*/)
+void create_letVar(const QueryLoc loc, const QName *varName, expr_t domainExpr, xqtref_t type)
 {
-  TRACE_VISIT_OUT();
-
-  xqtref_t type = (v.get_typedecl() == NULL ? NULL : pop_tstack());
-
-  if (v.get_kind() == VarGetsDecl::let_var)
-  {
-    expr_t domainExpr = pop_nodestack();
-
-    if (domainExpr->is_updating())
+  if (domainExpr->is_updating())
       throw XQUERY_EXCEPTION(err::XUST0001, ERROR_LOC(loc));
 
     // it's important to insert the debugger before the scope is pushed.
     // Otherwise, the variable in question would already be in scope for
     // the debugger but no value would be bound
-    QueryLoc lExpandedLocation = expandQueryLoc(v.get_name()->get_location(),
+    QueryLoc lExpandedLocation = expandQueryLoc(varName->get_location(),
                                                 domainExpr->get_loc());
 
     wrap_in_debugger_expr(domainExpr, lExpandedLocation);
 
     push_scope();
 
-    var_expr_t varExpr = bind_var(loc, v.get_name(), var_expr::let_var, type);
+    var_expr_t varExpr = bind_var(loc, varName, var_expr::let_var, type);
 
     let_clause* clause = new let_clause(theRootSctx,
                                         loc,
@@ -6078,6 +6118,19 @@
                                         domainExpr);
 
     theFlworClausesStack.push_back(clause);
+}
+
+void end_visit(const VarGetsDecl& v, void* /*visit_state*/)
+{
+  TRACE_VISIT_OUT();
+
+  xqtref_t type = (v.get_typedecl() == NULL ? NULL : pop_tstack());
+
+  if (v.get_kind() == VarGetsDecl::let_var)
+  {
+    expr_t domainExpr = pop_nodestack();
+
+    create_letVar(loc, v.get_name(), domainExpr, type);
   }
   else
   {
@@ -6377,9 +6430,23 @@
   for (int i = 0; i < (int)lList->size(); ++i)
   {
     GroupSpec* spec = (*lList)[i];
+    
     const QName* varname = spec->get_var_name();
-    const var_expr* ve = lookup_var(varname, loc, err::XPST0008);
-    group_vars.insert(ve);
+
+    const var_expr* ve = NULL;
+    if(spec->get_var_expr() == NULL)
+    {
+      ve = lookup_var(varname, loc, err::XPST0008);    
+    }
+    else
+    {
+      //variables can be explicitly shadowed, if we don't check for that
+      //we might have them become non-group variables incorrectly.
+      ve = lookup_var(varname, loc, zerr::ZXQP0000_NO_ERROR);
+    }
+
+    if(ve != NULL)
+      group_vars.insert(ve);
   }
 
   // The non-grouping vars are the vars in the difference of the 2 sets above.
@@ -6398,9 +6465,7 @@
   {
     push_nodestack(const_cast<var_expr *>(*i));
 
-    push_scope();
-
-    var_expr_t ve = bind_var(loc, (*i)->get_name(), var_expr::non_groupby_var);
+    var_expr_t ve = create_var(loc, (*i)->get_name(), var_expr::non_groupby_var);
     push_nodestack(ve.getp());
   }
 
@@ -6412,6 +6477,7 @@
 {
   TRACE_VISIT_OUT();
 
+  // NOTE: Now grouping vars have a expr for the input stream.
   // At this point, the nodestack contains a pair of var_exprs for each var X
   // defined by any clauses appearing before this GroupByClause. The first
   // var_expr in the pair corresponds to the input-stream var X, and the second
@@ -6425,28 +6491,40 @@
   std::vector<std::string> collations;
   group_clause::rebind_list_t grouping_rebind;
   group_clause::rebind_list_t nongrouping_rebind;
+  expr_t input_expr;
   var_expr_t input_var;
   var_expr_t output_var;
 
+  std::vector<var_expr_t> output_vars_helper;
   for (int i = (int)numGroupSpecs - 1; i >= 0; i--)
   {
     const GroupSpec& groupSpec = *groupSpecs[i];
 
     output_var = pop_nodestack_var();
-    input_var = pop_nodestack_var();
+    input_expr = pop_nodestack();
+
+    output_vars_helper.push_back(output_var);
 
     if (groupSpec.group_coll_spec() != NULL)
       collations.push_back(groupSpec.group_coll_spec()->get_uri().str());
     else
       collations.push_back ("");
 
-    wrapper_expr_t input_wrapper;
-    input_wrapper = new wrapper_expr(theRootSctx,
+    if(input_expr->get_expr_kind() == var_expr_kind)
+      input_expr = new wrapper_expr(theRootSctx,
                                      loc,
-                                     static_cast<expr*>(input_var.getp()));
-
-    grouping_rebind.push_back(std::pair<wrapper_expr_t, var_expr_t>(input_wrapper,
-                                                                    output_var));
+                                     input_expr.getp());
+
+    grouping_rebind.push_back(std::pair<expr_t, var_expr_t>(input_expr,
+                                                            output_var));
+  }
+
+  for(std::vector<var_expr_t>::reverse_iterator iter = output_vars_helper.rbegin();
+    iter != output_vars_helper.rend();
+    iter++)
+  {
+    push_scope();
+    bind_var(*iter, theSctx);
   }
 
   reverse(collations.begin(), collations.end());
@@ -6456,6 +6534,9 @@
   {
     input_var = pop_nodestack_var();
 
+    push_scope();
+    bind_var(output_var, theSctx);
+
     wrapper_expr_t input_wrapper;
     input_wrapper = new wrapper_expr(theRootSctx,
                                      loc,
@@ -6490,30 +6571,45 @@
 
 
 /*******************************************************************************
-  GroupSpec ::= "$" VarName ("collation" URILiteral)?
+  GroupSpec ::= "$" VarName (TypeDeclaration? ":=" ExprSingle)? ("collation" URILiteral)?
 ********************************************************************************/
 void* begin_visit(const GroupSpec& v)
 {
   TRACE_VISIT();
-
-  var_expr* e = lookup_var(v.get_var_name(), loc, err::XPST0008);
+  return no_state;
+}
+
+void end_visit(const GroupSpec& v, void* /*visit_state*/)
+{
+  TRACE_VISIT_OUT();
+
+  xqtref_t type = NULL;
+  if(v.get_var_expr() != NULL)
+  {
+    expr_t gvar_expr = wrap_in_atomization(pop_nodestack());
+
+    if(v.get_var_type() != NULL)
+    {
+      type = pop_tstack();
+      gvar_expr = wrap_in_type_promotion(gvar_expr, type);
+    }
+    
+    create_letVar(loc, v.get_var_name(), gvar_expr, type);
+  }
+
+  //wrap data
+  expr_t e = lookup_var(v.get_var_name(), loc, err::XPST0008);
 
   // Create a new var_expr gX, corresponding to the input-stream var X that
   // is referenced by this group spec. gX represents X in the output stream.
   // Push the var_exprs for both X and gX into the nodestack.
-  push_scope();
-
-  push_nodestack(e);
-
-  var_expr_t ve = bind_var(loc, v.get_var_name(), var_expr::groupby_var);
+
+  push_nodestack(e.getp());
+
+  var_expr_t ve =
+    create_var(loc, v.get_var_name(), var_expr::groupby_var, type);
+
   push_nodestack(ve.getp());
-
-  return no_state;
-}
-
-void end_visit(const GroupSpec& v, void* /*visit_state*/)
-{
-  TRACE_VISIT_OUT();
 }
 
 
@@ -9425,7 +9521,7 @@
   expr_t right = pop_nodestack();
   expr_t left  = pop_nodestack();
   concat_args.push_back(left);
- 
+
   //If the right leaf is the concat expr,
   //we add directly its leafs to the new concat expr.
   bool rightLeafIsConcatExpr = false;
@@ -9442,13 +9538,13 @@
       }
     }
   }
-  
+
   if(!rightLeafIsConcatExpr)
   {
     concat_args.push_back(right);
   }
 
-  rchandle<expr> concat = new fo_expr(theRootSctx, loc, GET_BUILTIN_FUNCTION(FN_CONCAT_N), concat_args); 
+  rchandle<expr> concat = new fo_expr(theRootSctx, loc, GET_BUILTIN_FUNCTION(FN_CONCAT_N), concat_args);
   push_nodestack(concat);
 }
 
@@ -11762,7 +11858,7 @@
   store::Item_t qnameItem;
   expand_elem_qname(qnameItem, qname, loc);
 
-  xqtref_t t = CTX_TM->create_named_atomic_type(qnameItem, TypeConstants::QUANT_ONE);  
+  xqtref_t t = CTX_TM->create_named_atomic_type(qnameItem, TypeConstants::QUANT_ONE);
 
   // some types that should never be parsed, like xs:untyped, are;
   // we catch them with is_simple()
@@ -12508,7 +12604,7 @@
 
 
 #ifndef ZORBA_NO_FULL_TEXT
-template<typename FTNodeType> bool flatten( ftnode *n ) 
+template<typename FTNodeType> bool flatten( ftnode *n )
 {
   if ( FTNodeType *const n2 = dynamic_cast<FTNodeType*>( n ) ) {
     typename FTNodeType::ftnode_list_t &list = n2->get_node_list();
@@ -12524,7 +12620,7 @@
 }
 #endif /* ZORBA_NO_FULL_TEXT */
 
-void *begin_visit (const FTAnd& v) 
+void *begin_visit (const FTAnd& v)
 {
   TRACE_VISIT ();
 #ifndef ZORBA_NO_FULL_TEXT
@@ -12533,7 +12629,7 @@
   return no_state;
 }
 
-void end_visit (const FTAnd& v, void* /*visit_state*/) 
+void end_visit (const FTAnd& v, void* /*visit_state*/)
 {
   TRACE_VISIT_OUT ();
 #ifndef ZORBA_NO_FULL_TEXT
@@ -12555,44 +12651,44 @@
 }
 
 
-void *begin_visit (const FTAnyallOption& v) 
-{
-  TRACE_VISIT ();
-  // nothing to do
-  return no_state;
-}
-
-
-void end_visit (const FTAnyallOption& v, void* /*visit_state*/) 
-{
-  TRACE_VISIT_OUT ();
-  // nothing to do
-}
-
-
-void *begin_visit (const FTBigUnit& v) 
-{
-  TRACE_VISIT ();
-  // nothing to do
-  return no_state;
-}
-
-
-void end_visit (const FTBigUnit& v, void* /*visit_state*/) 
-{
-  TRACE_VISIT_OUT ();
-  // nothing to do
-}
-
-void *begin_visit (const FTCaseOption& v) 
-{
-  TRACE_VISIT ();
-  // nothing to do
-  return no_state;
-}
-
-
-void end_visit (const FTCaseOption& v, void* /*visit_state*/) 
+void *begin_visit (const FTAnyallOption& v)
+{
+  TRACE_VISIT ();
+  // nothing to do
+  return no_state;
+}
+
+
+void end_visit (const FTAnyallOption& v, void* /*visit_state*/)
+{
+  TRACE_VISIT_OUT ();
+  // nothing to do
+}
+
+
+void *begin_visit (const FTBigUnit& v)
+{
+  TRACE_VISIT ();
+  // nothing to do
+  return no_state;
+}
+
+
+void end_visit (const FTBigUnit& v, void* /*visit_state*/)
+{
+  TRACE_VISIT_OUT ();
+  // nothing to do
+}
+
+void *begin_visit (const FTCaseOption& v)
+{
+  TRACE_VISIT ();
+  // nothing to do
+  return no_state;
+}
+
+
+void end_visit (const FTCaseOption& v, void* /*visit_state*/)
 {
   TRACE_VISIT_OUT ();
 #ifndef ZORBA_NO_FULL_TEXT
@@ -12607,7 +12703,7 @@
 }
 
 
-void *begin_visit (const FTContainsExpr& v) 
+void *begin_visit (const FTContainsExpr& v)
 {
   TRACE_VISIT ();
 #ifdef ZORBA_NO_FULL_TEXT
@@ -12618,7 +12714,7 @@
   return no_state;
 }
 
-void end_visit (const FTContainsExpr& v, void* /*visit_state*/) 
+void end_visit (const FTContainsExpr& v, void* /*visit_state*/)
 {
   TRACE_VISIT_OUT ();
 #ifndef ZORBA_NO_FULL_TEXT

=== added file 'test/rbkt/ExpQueryResults/zorba/groupby/groupby27.xml.res'
--- test/rbkt/ExpQueryResults/zorba/groupby/groupby27.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/groupby/groupby27.xml.res	2012-05-31 20:11:22 +0000
@@ -0,0 +1,1 @@
+<numbers kind="0" even="0">3 6 9</numbers><numbers kind="1" even="0">4</numbers><numbers kind="1" even="1">1 7</numbers><numbers kind="2" even="2">5</numbers><numbers kind="2" even="0">2 8</numbers>

=== added file 'test/rbkt/ExpQueryResults/zorba/groupby/groupby28.xml.res'
--- test/rbkt/ExpQueryResults/zorba/groupby/groupby28.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/groupby/groupby28.xml.res	2012-05-31 20:11:22 +0000
@@ -0,0 +1,1 @@
+<numbers even="true">2 4 6 8</numbers><numbers even="false">1 3 5 7</numbers>

=== added file 'test/rbkt/ExpQueryResults/zorba/groupby/groupby29.xml.res'
--- test/rbkt/ExpQueryResults/zorba/groupby/groupby29.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/groupby/groupby29.xml.res	2012-05-31 20:11:22 +0000
@@ -0,0 +1,1 @@
+<numbers group="0">2 3 4 6 8 9</numbers><numbers group="1">1 7</numbers><numbers group="2">5</numbers>

=== added file 'test/rbkt/ExpQueryResults/zorba/groupby/groupby30.xml.res'
--- test/rbkt/ExpQueryResults/zorba/groupby/groupby30.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/groupby/groupby30.xml.res	2012-05-31 20:11:22 +0000
@@ -0,0 +1,1 @@
+<grp y="1" even="0">2 4 6 8 10</grp><grp y="1" even="1">1 3 5 7 9</grp><grp y="2" even="1">1 3 5 7 9</grp><grp y="3" even="1">1 3 5 7 9</grp><grp y="4" even="1">1 3 5 7 9</grp><grp y="2" even="0">2 4 6 8 10</grp><grp y="3" even="0">2 4 6 8 10</grp><grp y="4" even="0">2 4 6 8 10</grp>

=== added file 'test/rbkt/Queries/zorba/groupby/groupby27.xq'
--- test/rbkt/Queries/zorba/groupby/groupby27.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/groupby/groupby27.xq	2012-05-31 20:11:22 +0000
@@ -0,0 +1,4 @@
+for $x in (1,2,3,4,5,6,7,8,9)
+let $kind := $x
+group by $kind := $kind mod 3, $even := $kind * ($x mod 2)
+return <numbers kind="{$kind}" even="{$even}">{$x}</numbers>

=== added file 'test/rbkt/Queries/zorba/groupby/groupby28.xq'
--- test/rbkt/Queries/zorba/groupby/groupby28.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/groupby/groupby28.xq	2012-05-31 20:11:22 +0000
@@ -0,0 +1,3 @@
+for $x in (1,2,3,4,5,6,7,8)
+group by $even as xs:integer := $x mod 2
+return <numbers even="{$even eq 0}">{$x}</numbers>

=== added file 'test/rbkt/Queries/zorba/groupby/groupby29.xq'
--- test/rbkt/Queries/zorba/groupby/groupby29.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/groupby/groupby29.xq	2012-05-31 20:11:22 +0000
@@ -0,0 +1,5 @@
+(: Explicit shadowing should be valid :)
+for $x in (1,2,3,4,5,6,7,8,9)
+let $kind := $x mod 3
+group by $kind := $kind * ($x mod 2)
+return <numbers group="{$kind}">{$x}</numbers>

=== added file 'test/rbkt/Queries/zorba/groupby/groupby30.xq'
--- test/rbkt/Queries/zorba/groupby/groupby30.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/groupby/groupby30.xq	2012-05-31 20:11:22 +0000
@@ -0,0 +1,4 @@
+for $x in 1 to 10, $y in 1 to 4
+let $org_y := $y
+group by $y, $y := $x mod 2
+return <grp y="{$org_y[1]}" even="{$y}">{$x}</grp>

-- 
Mailing list: https://launchpad.net/~zorba-coders
Post to     : zorba-coders@lists.launchpad.net
Unsubscribe : https://launchpad.net/~zorba-coders
More help   : https://help.launchpad.net/ListHelp

Reply via email to