← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/bug-900688 into lp:zorba

 

Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/bug-900688 into lp:zorba.

Requested reviews:
  Markos Zaharioudakis (markos-za)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/bug-900688/+merge/119998

Allow prolog variables to be referenced before they are declared (XQuery 3.0 feature) (fixes bug #900688)
-- 
https://code.launchpad.net/~zorba-coders/zorba/bug-900688/+merge/119998
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'src/compiler/parser/xquery_parser.y'
--- src/compiler/parser/xquery_parser.y	2012-08-14 11:13:50 +0000
+++ src/compiler/parser/xquery_parser.y	2012-08-16 18:30:28 +0000
@@ -1665,45 +1665,42 @@
     {
       std::auto_ptr<VarNameAndType> nt(dynamic_cast<VarNameAndType *>($2));
 
-      $$ = new VarDecl(LOC(@$),
-                       nt->theName,
-                       nt->theType,
-                       $4,
-                       nt->get_annotations(),
-                       true,    // global
-                       false);  // not external
+      $$ = new GlobalVarDecl(LOC(@$),
+                             nt->theName,
+                             nt->theType,
+                             $4,
+                             nt->get_annotations(),
+                             false);  // not external
 
-      dynamic_cast<VarDecl*>($$)->setComment(SYMTAB($1));
+      static_cast<GlobalVarDecl*>($$)->setComment(SYMTAB($1));
     }
   |
     DECLARE VarNameAndType EXTERNAL
     {
       std::auto_ptr<VarNameAndType> nt(dynamic_cast<VarNameAndType *>($2));
 
-      $$ = new VarDecl(LOC(@$),
-                       nt->theName,
-                       nt->theType,
-                       NULL,   // no init expr
-                       nt->get_annotations(),
-                       true,   // global
-                       true);  // external
+      $$ = new GlobalVarDecl(LOC(@$),
+                             nt->theName,
+                             nt->theType,
+                             NULL,   // no init expr
+                             nt->get_annotations(),
+                             true);  // external
 
-      dynamic_cast<VarDecl*>($$)->setComment(SYMTAB($1));
+      static_cast<GlobalVarDecl*>($$)->setComment(SYMTAB($1));
     }
   |
     DECLARE VarNameAndType EXTERNAL GETS ExprSingle
     {
       std::auto_ptr<VarNameAndType> nt(dynamic_cast<VarNameAndType *>($2));
 
-      $$ = new VarDecl(LOC(@$),
-                       nt->theName,
-                       nt->theType,
-                       $5,     // init expr
-                       nt->get_annotations(),
-                       true,   // global
-                       true);  // external
+      $$ = new GlobalVarDecl(LOC(@$),
+                             nt->theName,
+                             nt->theType,
+                             $5,     // init expr
+                             nt->get_annotations(),
+                             true);  // external
 
-      dynamic_cast<VarDecl*>($$)->setComment(SYMTAB($1));
+      static_cast<GlobalVarDecl*>($$)->setComment(SYMTAB($1));
     }
 ;
 
@@ -2271,7 +2268,8 @@
   |
     AnnotationList VARIABLE BlockVarDecl
     {
-      VarDeclStmt* vdecl = new VarDeclStmt(LOC(@$), static_cast<AnnotationListParsenode*>($1));
+      VarDeclStmt* vdecl = new VarDeclStmt(LOC(@$),
+                                           static_cast<AnnotationListParsenode*>($1));
       vdecl->add($3);
       $$ = vdecl;
     }
@@ -2281,51 +2279,38 @@
 BlockVarDecl :
     DOLLAR QNAME
     {
-      VarDecl* vd = new VarDecl(LOC(@$),
-                                static_cast<QName*>($2),
-                                NULL,  // no type
-                                NULL,  // no init expr
-                                NULL,  // no annotations
-                                false, // not global
-                                false);// not external
-      vd->set_global(false);
+      LocalVarDecl* vd = new LocalVarDecl(LOC(@$),
+                                          static_cast<QName*>($2),
+                                          NULL,  // no type
+                                          NULL,  // no init expr
+                                          NULL); // no annotations
       $$ = vd;
     }
   | DOLLAR QNAME TypeDeclaration
     {
-      VarDecl* vd = new VarDecl(LOC(@$),
-                                static_cast<QName*>($2),
-                                dynamic_cast<SequenceType*>($3), // type
-                                NULL,  // no init expr
-                                NULL,  // no annotations
-                                false, // not global
-                                false);// not external
-
-      vd->set_global(false);
+      LocalVarDecl* vd = new LocalVarDecl(LOC(@$),
+                                          static_cast<QName*>($2),
+                                          dynamic_cast<SequenceType*>($3), // type
+                                          NULL,  // no init expr
+                                          NULL); // no annotations
       $$ = vd;
     }
   | DOLLAR QNAME GETS ExprSingle
     {
-      VarDecl* vd = new VarDecl(LOC(@$),
-                                static_cast<QName*>($2),
-                                NULL,  // no type
-                                $4,    // init expr
-                                NULL,  // no annotations
-                                false, // not global
-                                false);// not external
-      vd->set_global(false);
+      LocalVarDecl* vd = new LocalVarDecl(LOC(@$),
+                                          static_cast<QName*>($2),
+                                          NULL,  // no type
+                                          $4,    // init expr
+                                          NULL); // no annotations
       $$ = vd;
     }
   | DOLLAR QNAME TypeDeclaration GETS ExprSingle
     {
-      VarDecl* vd = new VarDecl(LOC(@$),
-                                static_cast<QName*>($2),
-                                dynamic_cast<SequenceType*>($3), // type
-                                $5,    // init expr
-                                NULL,  // no annotations
-                                false, // not global
-                                false);// not external
-      vd->set_global(false);
+      LocalVarDecl* vd = new LocalVarDecl(LOC(@$),
+                                          static_cast<QName*>($2),
+                                          dynamic_cast<SequenceType*>($3), // type
+                                          $5,    // init expr
+                                          NULL); // no annotations
       $$ = vd;
     }
   ;

=== modified file 'src/compiler/parsetree/parsenode_print_xml_visitor.cpp'
--- src/compiler/parsetree/parsenode_print_xml_visitor.cpp	2012-08-14 11:13:50 +0000
+++ src/compiler/parsetree/parsenode_print_xml_visitor.cpp	2012-08-16 18:30:28 +0000
@@ -370,7 +370,7 @@
 
 NO_END_TAG (ValueComp)
 
-void *begin_visit(const VarDecl &n)
+void* begin_visit(const GlobalVarDecl &n)
 {
     INDENT;
 
@@ -384,6 +384,20 @@
 }
 
 
+void* begin_visit(const LocalVarDecl &n)
+{
+    INDENT;
+
+    os << "<LocalVarDecl pos='" << n.get_location() << "' var='"
+       << n.get_var_name()->get_qname() << "' ptr='" << &n << "'";
+
+    os << ">";
+
+    INDENT_INC; NL;
+    return no_state;
+}
+
+
 void *begin_visit(const VarGetsDecl &n)
 {
     INDENT;
@@ -808,7 +822,8 @@
 BEGIN_END_TAG (IndexKeySpec)
 BEGIN_END_TAG (IndexKeyList)
 BEGIN_END_TAG (IntegrityConstraintDecl)
-END_TAG (VarDecl)
+END_TAG (GlobalVarDecl)
+END_TAG (LocalVarDecl)
 END_TAG (VarGetsDecl)
 BEGIN_END_TAG (VarGetsDeclList)
 END_TAG (VarInDecl)

=== modified file 'src/compiler/parsetree/parsenode_print_xqdoc_visitor.cpp'
--- src/compiler/parsetree/parsenode_print_xqdoc_visitor.cpp	2012-08-14 11:13:50 +0000
+++ src/compiler/parsetree/parsenode_print_xqdoc_visitor.cpp	2012-08-16 18:30:28 +0000
@@ -900,10 +900,8 @@
   map<zstring, zstring>::iterator ite = theNamespaceMap.find(aPrefix);
   if (ite == theNamespaceMap.end())
   {
-    throw ZORBA_EXCEPTION(
-      zerr::ZXQD0001_PREFIX_NOT_DECLARED,
-      ERROR_PARAMS( aPrefix, aLocalName, aLocation )
-    );
+    throw ZORBA_EXCEPTION(zerr::ZXQD0001_PREFIX_NOT_DECLARED,
+    ERROR_PARAMS(aPrefix, aLocalName, aLocation ));
   }
 
   zstring lNS = ite->second;
@@ -936,13 +934,10 @@
 }
 
 
-XQDOC_NO_BEGIN_TAG (VarDecl)
+XQDOC_NO_BEGIN_TAG (GlobalVarDecl)
 
-void end_visit(const VarDecl& n, void*)
+void end_visit(const GlobalVarDecl& n, void*)
 {
-  if (!n.is_global())
-    return;
-
   store::Item_t lVariableQName, lUriQName;
   store::Item_t lVariableElem, lUriElem, lUriText;
 
@@ -1276,6 +1271,7 @@
 XQDOC_NO_BEGIN_END_TAG (ValidateExpr)
 XQDOC_NO_BEGIN_END_TAG (ValueComp)
 XQDOC_NO_BEGIN_END_TAG (VarBinding)
+XQDOC_NO_BEGIN_END_TAG( LocalVarDecl )
 XQDOC_NO_BEGIN_END_TAG (VarGetsDecl)
 XQDOC_NO_BEGIN_END_TAG (VarGetsDeclList)
 XQDOC_NO_BEGIN_END_TAG (VarInDecl)

=== modified file 'src/compiler/parsetree/parsenode_print_xquery_visitor.cpp'
--- src/compiler/parsetree/parsenode_print_xquery_visitor.cpp	2012-08-14 11:13:50 +0000
+++ src/compiler/parsetree/parsenode_print_xquery_visitor.cpp	2012-08-16 18:30:28 +0000
@@ -1044,23 +1044,49 @@
     DEFAULT_VISIT (IndexKeyList)
     DEFAULT_VISIT (IntegrityConstraintDecl)
 
-    void* begin_visit(const VarDecl& n)
+    void* begin_visit(const GlobalVarDecl& n)
     {
       os << "declare variable $" << n.get_var_name()->get_qname();
-      if(n.get_var_type())
+
+      if (n.get_var_type())
       {
         n.get_var_type()->accept(*this);
       }
-      if(n.is_extern())
+
+      if (n.is_extern())
       {
         os << "external";
-      } else if(n.get_binding_expr()) {
-        os << ":=";
-        n.get_binding_expr()->accept(*this);
-      }
-      return 0;
-    }
-    DEFAULT_END_VISIT (VarDecl)
+      }
+
+      if (n.get_binding_expr())
+      {
+        os << ":=";
+        n.get_binding_expr()->accept(*this);
+      }
+      return 0;
+    }
+
+    DEFAULT_END_VISIT (GlobalVarDecl)
+
+    void* begin_visit(const LocalVarDecl& n)
+    {
+      os << "variable $" << n.get_var_name()->get_qname();
+
+      if (n.get_var_type())
+      {
+        n.get_var_type()->accept(*this);
+      }
+
+      if (n.get_binding_expr())
+      {
+        os << ":=";
+        n.get_binding_expr()->accept(*this);
+      }
+      return 0;
+    }
+
+    DEFAULT_END_VISIT (LocalVarDecl)
+
 
     void* begin_visit(const VarGetsDecl& n)
     {

=== modified file 'src/compiler/parsetree/parsenode_visitor.h'
--- src/compiler/parsetree/parsenode_visitor.h	2012-08-14 11:13:50 +0000
+++ src/compiler/parsetree/parsenode_visitor.h	2012-08-16 18:30:28 +0000
@@ -133,7 +133,8 @@
   DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( IndexKeySpec );
   DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( IndexKeyList );
   DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( IntegrityConstraintDecl );
-  DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( VarDecl );
+  DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( GlobalVarDecl );
+  DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( LocalVarDecl );
   DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( VarGetsDecl );
   DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( VarGetsDeclList );
   DECL_PARSENODE_VISITOR_VISIT_MEM_FNS( VarInDecl );

=== modified file 'src/compiler/parsetree/parsenodes.cpp'
--- src/compiler/parsetree/parsenodes.cpp	2012-08-14 11:13:50 +0000
+++ src/compiler/parsetree/parsenodes.cpp	2012-08-16 18:30:28 +0000
@@ -720,36 +720,25 @@
   VarValue ::= ExprSingle
 
   VarDefaultValue ::= ExprSingle
-
-
-  Local declarations:
-  -------------------
-
-  VarDeclStatement ::= ("local" Annotation*)? "variable"
-                       "$" VarName TypeDeclaration? (":=" ExprSingle)?
-                       ("," "$" VarName TypeDeclaration? (":=" ExprSingle)?)* ";"
 ********************************************************************************/
-VarDecl::VarDecl(
+GlobalVarDecl::GlobalVarDecl(
     const QueryLoc& loc,
     QName* varname,
     SequenceType* type_decl,
     exprnode* init_expr,
     AnnotationListParsenode* annotations,
-    bool global,
     bool external)
   :
   VarDeclWithInit(loc, varname, type_decl, init_expr),
   theIsExternal(external),
-  theIsGlobal(global),
   theAnnotations(annotations)
 {
 }
 
 
-void VarDecl::accept(parsenode_visitor& v) const
+void GlobalVarDecl::accept(parsenode_visitor& v) const
 {
   BEGIN_VISITOR();
-  ACCEPT(theAnnotations);
   ACCEPT(theType);
   ACCEPT(theExpr);
   END_VISITOR();
@@ -789,9 +778,9 @@
 }
 
 
-ulong FunctionDecl::get_param_count() const
+csize FunctionDecl::get_param_count() const
 {
-  return theParams == NULL ? 0 : (ulong)theParams->size();
+  return theParams == NULL ? 0 : theParams->size();
 }
 
 
@@ -1216,9 +1205,9 @@
   {
     VarDeclStmt* vdecl = static_cast<VarDeclStmt*>(statement);
 
-    ulong numDecls = vdecl->size();
+    csize numDecls = vdecl->size();
 
-    for (ulong i = 0; i < numDecls; ++i)
+    for (csize i = 0; i < numDecls; ++i)
     {
       theStatements.push_back(vdecl->getDecl(i));
     }
@@ -1242,9 +1231,10 @@
 {
 }
 
+
 void VarDeclStmt::add(parsenode* decl)
 {
-  VarDecl* varDecl = dynamic_cast<VarDecl*>(decl);
+  LocalVarDecl* varDecl = dynamic_cast<LocalVarDecl*>(decl);
   if (varDecl != NULL)
   {
     varDecl->set_annotations(theAnnotations);
@@ -1253,6 +1243,7 @@
   theDecls.push_back(decl);
 }
 
+
 void VarDeclStmt::accept(parsenode_visitor& v) const
 {
   assert(false);
@@ -1260,6 +1251,37 @@
 
 
 /*******************************************************************************
+  Local declarations:
+  -------------------
+
+  VarDeclStatement ::= ("local" Annotation*)? "variable"
+                       "$" VarName TypeDeclaration? (":=" ExprSingle)?
+                       ("," "$" VarName TypeDeclaration? (":=" ExprSingle)?)* ";"
+********************************************************************************/
+LocalVarDecl::LocalVarDecl(
+    const QueryLoc& loc,
+    QName* varname,
+    SequenceType* type_decl,
+    exprnode* init_expr,
+    AnnotationListParsenode* annotations)
+  :
+  VarDeclWithInit(loc, varname, type_decl, init_expr),
+  theAnnotations(annotations)
+{
+}
+
+
+void LocalVarDecl::accept(parsenode_visitor& v) const
+{
+  BEGIN_VISITOR();
+  ACCEPT(theAnnotations);
+  ACCEPT(theType);
+  ACCEPT(theExpr);
+  END_VISITOR();
+}
+
+
+/*******************************************************************************
 
 ********************************************************************************/
 void AssignExpr::accept(parsenode_visitor& v) const

=== modified file 'src/compiler/parsetree/parsenodes.h'
--- src/compiler/parsetree/parsenodes.h	2012-08-14 11:13:50 +0000
+++ src/compiler/parsetree/parsenodes.h	2012-08-16 18:30:28 +0000
@@ -950,30 +950,24 @@
 /*******************************************************************************
 
 ********************************************************************************/
-class VarDecl : public VarDeclWithInit
+class GlobalVarDecl : public VarDeclWithInit
 {
 protected:
   bool theIsExternal;
-  bool theIsGlobal;
 
   rchandle<AnnotationListParsenode> theAnnotations;
 
 public:
-  VarDecl(
+  GlobalVarDecl(
     const QueryLoc& loc,
     QName* varname,
     SequenceType* type_decl,
     exprnode* init_expr,
     AnnotationListParsenode* annotations,
-    bool global,
     bool external);
 
   bool is_extern() const { return theIsExternal; }
 
-  bool is_global() const { return theIsGlobal; }
-
-  void set_global(bool global) { theIsGlobal = global; }
-
   void set_annotations(rchandle<AnnotationListParsenode> annotations)
   {
     theAnnotations = annotations;
@@ -1058,7 +1052,7 @@
 
   rchandle<ParamList> get_paramlist() const { return theParams; }
 
-  ulong get_param_count() const;
+  csize get_param_count() const;
 
   rchandle<SequenceType> get_return_type() const { return theReturnType; }
 
@@ -1640,7 +1634,9 @@
 
 
 /*******************************************************************************
-
+  VarDeclStatement ::= ("local" Annotation*)? "variable"
+                       "$" VarName TypeDeclaration? (":=" ExprSingle)?
+                       ("," "$" VarName TypeDeclaration? (":=" ExprSingle)?)* ";"
 ********************************************************************************/
 class VarDeclStmt : public exprnode
 {
@@ -1664,6 +1660,33 @@
 /*******************************************************************************
 
 ********************************************************************************/
+class LocalVarDecl : public VarDeclWithInit
+{
+protected:
+  rchandle<AnnotationListParsenode> theAnnotations;
+
+public:
+  LocalVarDecl(
+    const QueryLoc& loc,
+    QName* varname,
+    SequenceType* type_decl,
+    exprnode* init_expr,
+    AnnotationListParsenode* annotations);
+
+  void set_annotations(rchandle<AnnotationListParsenode> annotations)
+  {
+    theAnnotations = annotations;
+  }
+
+  AnnotationListParsenode* get_annotations() const { return theAnnotations.getp(); }
+
+  void accept(parsenode_visitor&) const;
+};
+
+
+/*******************************************************************************
+
+********************************************************************************/
 class AssignExpr : public exprnode
 {
   rchandle<QName>    theName;

=== modified file 'src/compiler/translator/prolog_graph.cpp'
--- src/compiler/translator/prolog_graph.cpp	2012-08-14 11:13:50 +0000
+++ src/compiler/translator/prolog_graph.cpp	2012-08-16 18:30:28 +0000
@@ -24,6 +24,8 @@
 #include "zorbatypes/zstring.h"
 
 #include "diagnostics/xquery_exception.h"
+#include "diagnostics/dict.h"
+#include "diagnostics/util_macros.h"
 
 namespace zorba 
 {
@@ -38,18 +40,36 @@
   zstring varName;
   if ( v )
     varName = BUILD_STRING('$', v->getVarExpr()->get_name()->getStringValue());
-  throw XQUERY_EXCEPTION(err::XQST0054, ERROR_PARAMS(varName), ERROR_LOC(loc));
-}
-
-
-/*******************************************************************************
-   This method is part of the mechanism for detecting cycles in the dependency
+
+  RAISE_ERROR(err::XQST0054, loc, ERROR_PARAMS(varName));
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+void PrologGraph::addEdge(const PrologGraphVertex& v1, const PrologGraphVertex& v2)
+{
+  if (v1.isVar() && v2.isVar() && v1.getVarExpr() == v2.getVarExpr())
+  {
+    zstring varName = '$' + v1.getVarExpr()->get_name()->getStringValue();
+
+    RAISE_ERROR(err::XPST0008, v2.getVarExpr()->get_loc(),
+    ERROR_PARAMS(varName, ZED(VariabledUndeclared)));
+  }
+
+  addEdge(theGraph, v1, v2);
+}
+
+
+/*******************************************************************************
+  This method is part of the mechanism for detecting cycles in the dependency
   graph among prolog variables. The method does not actually detect the cycles
   but re-orders the declarations of prolog vars (i.e., reorders theGlobalVars
   list) so that if var v2 depends on var v1, then v1 appears before v2 in the
   list (and as a result, v1 will be evaluated before v2 during runtime).
 
-  Circular dependencies among prolog vars can appear only when udfs are invloved.
+  Circular dependencies among prolog vars can appear only when udfs are involved.
   Here is an example:
 
   declare variable $var := local:func1();

=== modified file 'src/compiler/translator/prolog_graph.h'
--- src/compiler/translator/prolog_graph.h	2012-08-14 11:13:50 +0000
+++ src/compiler/translator/prolog_graph.h	2012-08-16 18:30:28 +0000
@@ -77,6 +77,10 @@
 
   Kind getKind() const { return theKind; }
 
+  bool isVar() const { return theKind == VAR; }
+
+  bool isUDF() const { return theKind == FUN; }
+
   const function* getFunction() const
   {
     assert(theKind == FUN);
@@ -166,10 +170,7 @@
     theFuncDecls.push_back(v);
   }
 
-  void addEdge(const PrologGraphVertex& v1, const PrologGraphVertex& v2)
-  {
-    addEdge(theGraph, v1, v2);
-  }
+  void addEdge(const PrologGraphVertex& v1, const PrologGraphVertex& v2);
 
   void reorder_globals(std::list<GlobalBinding>& prologVarBindings);
 

=== modified file 'src/compiler/translator/translator.cpp'
--- src/compiler/translator/translator.cpp	2012-08-14 11:13:50 +0000
+++ src/compiler/translator/translator.cpp	2012-08-16 18:30:28 +0000
@@ -916,7 +916,7 @@
 *******************************************************************************/
 inline bool inUDFBody()
 {
-  return !theCurrentPrologVFDecl.isNull();
+  return (!theCurrentPrologVFDecl.isNull() && theCurrentPrologVFDecl.isUDF());
 }
 
 
@@ -3246,21 +3246,105 @@
       continue;
     }
 
+#if 1
+    const GlobalVarDecl* var_decl = it->dyn_cast<GlobalVarDecl>().getp();
+
+    if (var_decl != NULL &&
+        theSctx->xquery_version() >= StaticContextConsts::xquery_version_3_0)
+    {
+      const QueryLoc& loc = var_decl->get_location();
+
+      store::Item_t qnameItem;
+      expand_no_default_qname(qnameItem, var_decl->get_var_name(), loc);
+
+      // All vars declared in a module must be in the same namespace as the module
+      if (! theModuleNamespace.empty() &&
+          qnameItem->getNamespace() != theModuleNamespace)
+      {
+        RAISE_ERROR(err::XQST0048, loc, ERROR_PARAMS(qnameItem->getStringValue()));
+      }
+
+      var_expr_t ve = create_var(loc, qnameItem, var_expr::prolog_var);
+
+      if (var_decl->is_extern())
+        ve->set_external(true);
+
+      xqtref_t type;
+      if (var_decl->get_var_type() != NULL)
+      {
+        var_decl->get_var_type()->accept(*this);
+
+        type = pop_tstack();
+
+        ve->set_type(type);
+      }
+
+      AnnotationListParsenode* annotations = var_decl->get_annotations();
+      if (annotations)
+      {
+        if (theSctx->xquery_version() < StaticContextConsts::xquery_version_3_0)
+        {
+          RAISE_ERROR(err::XPST0003, loc, ERROR_PARAMS(ZED(XPST0003_Annotations)));
+        }
+
+        annotations->accept(*this);
+
+        if (theAnnotations)
+        {
+          if (ZANN_CONTAINS(fn_private))
+            ve->set_private(true);
+
+          if (ZANN_CONTAINS(zann_assignable))
+          {
+            ve->set_mutable(true);
+          }
+          else if (ZANN_CONTAINS(zann_nonassignable))
+          {
+            ve->set_mutable(false);
+          }
+          else
+          {
+            ve->set_mutable(theSctx->is_feature_set(feature::scripting));
+          }
+        }
+        else
+        {
+          ve->set_mutable(theSctx->is_feature_set(feature::scripting));
+        }
+      }
+
+      theAnnotations = NULL;
+
+      // Put a mapping between the var name and the var_expr in the local sctx.
+      // Raise error if var name exists already in local sctx obj.
+      bind_var(ve, theSctx);
+
+      // Make sure that there is no other prolog var with the same name in any of
+      // modules translated so far.
+      bind_var(ve, theModulesInfo->globalSctx.get());
+
+      // If this is a library module, register the var in the exported sctx as well.
+      if (export_sctx != NULL)
+        bind_var(ve, export_sctx);
+
+      continue;
+    }
+#endif
+
     const FunctionDecl* func_decl = it->dyn_cast<FunctionDecl>().getp();
 
-    // skip variable and option declarations.
     if (func_decl == NULL)
       continue;
 
-    AnnotationListParsenode* lAnns = func_decl->get_annotations();
-    if (lAnns)
+    AnnotationListParsenode* annotations = func_decl->get_annotations();
+    if (annotations)
     {
       if (theSctx->xquery_version() < StaticContextConsts::xquery_version_3_0)
       {
         RAISE_ERROR(err::XPST0003, loc, ERROR_PARAMS(ZED(XPST0003_Annotations)));
       }
 
-      lAnns->accept(*this);
+      annotations->accept(*this);
     }
 
     const QueryLoc& loc = func_decl->get_location();
@@ -3337,9 +3421,7 @@
     }
 
     // Create the function signature.
-    bool isVariadic = (theAnnotations ?
-                       ZANN_CONTAINS(zann_variadic):
-                       false);
+    bool isVariadic = (theAnnotations ? ZANN_CONTAINS(zann_variadic): false);
 
     signature sig(qnameItem, paramTypes, returnType, isVariadic);
 
@@ -3713,7 +3795,7 @@
   // theCurrentPrologVFDecl might be null in case of inline functions
   // inline functions currently can't be sequential anyway
   // hence, we can always lazy evaluation
-  if (!theCurrentPrologVFDecl.isNull())
+  if (inUDFBody())
   {
     //lc->setLazyEval(!f->isSequential());
 
@@ -3744,8 +3826,6 @@
 
 /*******************************************************************************
 
-  VarDecl is used to represent both global and block-local var declarations.
-
   Global declarations:
   --------------------
 
@@ -3764,22 +3844,8 @@
 
   Note: the applicable annotations are private vs public, and assignable vs
   non-assignable.
-
-
-  Local declarations:
-  -------------------
-
-  VarDeclStatement ::= ("local" Annotation*)? "variable"
-                       "$" VarName TypeDeclaration? (":=" ExprSingle)?
-                       ("," "$" VarName TypeDeclaration? (":=" ExprSingle)?)* ";"
-
-  Note: The initializing ExprSingle in VarValue must be a non-updating expr.
-
-  Note: The applicable annotations are assignable vs non-assignable.
-
-  Note: Local var decls may appear only as direct operands of block exprs.
 ********************************************************************************/
-void* begin_visit(const VarDecl& v)
+void* begin_visit(const GlobalVarDecl& v)
 {
   TRACE_VISIT();
 
@@ -3788,81 +3854,40 @@
 
   var_expr_t ve;
 
-  if (v.is_global())
+  if (theSctx->xquery_version() >= StaticContextConsts::xquery_version_3_0)
+  {
+    ve = lookup_var(qnameItem, loc, err::XPST0008);
+
+    assert(ve);
+  }
+  else
   {
     ve = create_var(loc, qnameItem, var_expr::prolog_var);
 
     if (v.is_extern())
       ve->set_external(true);
-
-    thePrologGraph.addVarVertex(ve);
-    theCurrentPrologVFDecl = PrologGraphVertex(ve);
-  }
-  else
-  {
-    if (theNodeStack.top()->get_expr_kind() != block_expr_kind)
-    {
-      ZORBA_ASSERT(false);
-    }
-
-    ve = create_var(loc, qnameItem, var_expr::local_var);
-  }
-
-  push_nodestack(ve.getp());
+  }
+
+  thePrologGraph.addVarVertex(ve);
+  theCurrentPrologVFDecl = PrologGraphVertex(ve);
+
+  push_nodestack(ve);
+
   return no_state;
 }
 
 
-void end_visit(const VarDecl& v, void* /*visit_state*/)
+void end_visit(const GlobalVarDecl& v, void* /*visit_state*/)
 {
   TRACE_VISIT_OUT();
 
-  if (v.is_global())
-    theCurrentPrologVFDecl.setNull();
+  theCurrentPrologVFDecl.setNull();
 
   expr_t initExpr = (v.get_binding_expr() == NULL ? expr_t(NULL) : pop_nodestack());
 
   var_expr_t ve = dynamic_cast<var_expr*>(pop_nodestack().getp());
 
-  if (theAnnotations)
-  {
-    if (v.is_global())
-    {
-      if (ZANN_CONTAINS(fn_private))
-        ve->set_private(true);
-    }
-
-    if (ZANN_CONTAINS(zann_assignable))
-    {
-      ve->set_mutable(true);
-    }
-    else if (ZANN_CONTAINS(zann_nonassignable))
-    {
-      ve->set_mutable(false);
-    }
-    else if (v.is_global())
-    {
-      ve->set_mutable(theSctx->is_feature_set(feature::scripting));
-    }
-  }
-  else if (v.is_global())
-  {
-    ve->set_mutable(theSctx->is_feature_set(feature::scripting));
-  }
-
-  xqtref_t type;
-  if (v.get_var_type() != NULL)
-  {
-    type = pop_tstack();
-
-    ve->set_type(type);
-  }
-
-  // Put a mapping between the var name and the var_expr in the local sctx.
-  // Raise error if var name exists already in local sctx obj.
-  bind_var(ve, theSctx);
-
-  if (v.is_global())
+  if (theSctx->xquery_version() < StaticContextConsts::xquery_version_3_0)
   {
     // All vars declared in a module must be in the same namespace as the module
     if (! theModuleNamespace.empty() &&
@@ -3871,57 +3896,72 @@
       RAISE_ERROR(err::XQST0048, loc, ERROR_PARAMS(ve->get_name()->getStringValue()));
     }
 
+    if (theAnnotations)
+    {
+      if (ZANN_CONTAINS(fn_private))
+        ve->set_private(true);
+
+      if (ZANN_CONTAINS(zann_assignable))
+      {
+        ve->set_mutable(true);
+      }
+      else if (ZANN_CONTAINS(zann_nonassignable))
+      {
+        ve->set_mutable(false);
+      }
+      else
+      {
+        ve->set_mutable(theSctx->is_feature_set(feature::scripting));
+      }
+    }
+    else
+    {
+      ve->set_mutable(theSctx->is_feature_set(feature::scripting));
+    }
+
+    theAnnotations = NULL;
+
+    // Put a mapping between the var name and the var_expr in the local sctx.
+    // Raise error if var name exists already in local sctx obj.
+    bind_var(ve, theSctx);
+
     // Make sure that there is no other prolog var with the same name in any of
     // modules translated so far.
     bind_var(ve, theModulesInfo->globalSctx.get());
-
-    // Make sure the initExpr is a simple expr.
-    if (initExpr != NULL)
-    {
-      expr::checkSimpleExpr(initExpr);
-      ve->set_has_initializer(true);
-    }
-
+    
     // If this is a library module, register the var in the exported sctx as well.
     if (export_sctx != NULL)
       bind_var(ve, export_sctx);
-
-#ifdef ZORBA_WITH_DEBUGGER
-    if (initExpr != NULL && theCCB->theDebuggerCommons != NULL)
-    {
-      QueryLoc lExpandedLocation = expandQueryLoc(v.get_var_name()->get_location(),
-                                                  initExpr->get_loc());
-
-      wrap_in_debugger_expr(initExpr, lExpandedLocation, false, true);
-    }
-#endif
-
-    // The ve and its associated intExpr will be put into var_decl_expr that
-    // will creaated by the wrap_in_globalvar_assign() method when it is called
-    // at the end of the translation of each module.
-    thePrologVars.push_back(GlobalBinding(ve, initExpr, v.is_extern()));
-  }
-  else
-  {
-    // The ve and its associated intExpr will be put into var_decl_expr that
-    // will be created by the translation of the parent block expr, immediately
-    // after returning from this method.
-    push_nodestack(ve.getp());
-
-#ifdef ZORBA_WITH_DEBUGGER
-    if (initExpr != NULL && theCCB->theDebuggerCommons != NULL)
-    {
-      QueryLoc lExpandedLocation = 
-      expandQueryLoc(v.get_var_name()->get_location(), initExpr->get_loc());
-
-      wrap_in_debugger_expr(initExpr, lExpandedLocation, false, true);
-    }
-#endif
-
-    push_nodestack(initExpr);
-  }
-
-  theAnnotations = NULL;
+  }
+
+  xqtref_t type;
+  if (v.get_var_type() != NULL)
+  {
+    type = pop_tstack();
+    ve->set_type(type);
+  }
+
+  // Make sure the initExpr is a simple expr.
+  if (initExpr != NULL)
+  {
+    expr::checkSimpleExpr(initExpr);
+    ve->set_has_initializer(true);
+  }
+
+#ifdef ZORBA_WITH_DEBUGGER
+  if (initExpr != NULL && theCCB->theDebuggerCommons != NULL)
+  {
+    QueryLoc lExpandedLocation = expandQueryLoc(v.get_var_name()->get_location(),
+                                                initExpr->get_loc());
+
+    wrap_in_debugger_expr(initExpr, lExpandedLocation, false, true);
+  }
+#endif
+
+  // The ve and its associated intExpr will be put into var_decl_expr that
+  // will creaated by the wrap_in_globalvar_assign() method when it is called
+  // at the end of the translation of each module.
+  thePrologVars.push_back(GlobalBinding(ve, initExpr, v.is_extern()));
 }
 
 
@@ -5487,7 +5527,7 @@
   {
     v[i]->accept(*this);
 
-    if (dynamic_cast<const VarDecl*>(v[i]) != NULL)
+    if (dynamic_cast<const LocalVarDecl*>(v[i]) != NULL)
     {
       expr_t val = pop_nodestack();
       var_expr_t ve = pop_nodestack().cast<var_expr>();
@@ -5577,12 +5617,86 @@
   Note: Each individual var decl in a VarDeclStatement is parsed into a VarDecl
   parsenode.
 
+  Note: The applicable annotations are assignable vs non-assignable.
+
   Note: The parser makes sure that if a VarDeclStatement does not appear as a
   direct child of a BlockBody, it is wrapped by a BlockBody. Furthermore, the
   parser will flatten-out the VarDeclStatement parsenode by placing its children
   as direct children of the enclosing BlockBody. As a result, VarDeclStatement
-  parsenodes do not appear at all in the final AST.
+  parsenodes do not appear at all in the final AST, and local var decls may
+  appear only as direct operands of block exprs.
 ********************************************************************************/
+void* begin_visit(const LocalVarDecl& v)
+{
+  TRACE_VISIT();
+
+  store::Item_t qnameItem;
+  expand_no_default_qname(qnameItem, v.get_var_name(), loc);
+
+  if (theNodeStack.top()->get_expr_kind() != block_expr_kind)
+  {
+    ZORBA_ASSERT(false);
+  }
+
+  var_expr_t ve = create_var(loc, qnameItem, var_expr::local_var);
+
+  push_nodestack(ve.getp());
+
+  return no_state;
+}
+
+
+void end_visit(const LocalVarDecl& v, void* /*visit_state*/)
+{
+  TRACE_VISIT_OUT();
+
+  expr_t initExpr = (v.get_binding_expr() == NULL ? expr_t(NULL) : pop_nodestack());
+
+  var_expr_t ve = dynamic_cast<var_expr*>(pop_nodestack().getp());
+
+  if (theAnnotations)
+  {
+    if (ZANN_CONTAINS(zann_assignable))
+    {
+      ve->set_mutable(true);
+    }
+    else if (ZANN_CONTAINS(zann_nonassignable))
+    {
+      ve->set_mutable(false);
+    }
+  }
+
+  xqtref_t type;
+  if (v.get_var_type() != NULL)
+  {
+    type = pop_tstack();
+
+    ve->set_type(type);
+  }
+
+  // Put a mapping between the var name and the var_expr in the local sctx.
+  // Raise error if var name exists already in local sctx obj.
+  bind_var(ve, theSctx);
+
+  // The ve and its associated intExpr will be put into var_decl_expr that
+  // will be created by the translation of the parent block expr, immediately
+  // after returning from this method.
+  push_nodestack(ve.getp());
+
+#ifdef ZORBA_WITH_DEBUGGER
+  if (initExpr != NULL && theCCB->theDebuggerCommons != NULL)
+  {
+    QueryLoc lExpandedLocation = 
+    expandQueryLoc(v.get_var_name()->get_location(), initExpr->get_loc());
+
+    wrap_in_debugger_expr(initExpr, lExpandedLocation, false, true);
+  }
+#endif
+
+  push_nodestack(initExpr);
+
+  theAnnotations = NULL;
+}
 
 
 /*******************************************************************************
@@ -10330,8 +10444,7 @@
     // as a non-leaf function.
     if (f->isUdf())
     {
-      if (! theCurrentPrologVFDecl.isNull() &&
-          theCurrentPrologVFDecl.getKind() == PrologGraphVertex::FUN)
+      if (inUDFBody())
       {
         function* f1 = const_cast<function*>(theCurrentPrologVFDecl.getFunction());
         user_function* udf = dynamic_cast<user_function*>(f1);

=== modified file 'src/context/static_context.cpp'
--- src/context/static_context.cpp	2012-08-14 11:13:50 +0000
+++ src/context/static_context.cpp	2012-08-16 18:30:28 +0000
@@ -210,8 +210,6 @@
   theHasInitializer(v->has_initializer()),
   theVarExpr(v.getp())
 {
-  if (theKind == var_expr::prolog_var)
-    v->set_var_info(this);
 }
 
 
@@ -2198,12 +2196,25 @@
   VarInfo_t vi = varExpr->get_var_info();
 
   if (vi == NULL)
+  {
     vi = new VarInfo(varExpr);
 
-  if (!theVariablesMap->insert(qname, vi))
+    if (!theVariablesMap->insert(qname, vi))
+    {
+      throw XQUERY_EXCEPTION_VAR(err,
+      ERROR_PARAMS(qname->getStringValue()), ERROR_LOC(loc));
+    }
+
+    if (varExpr->get_kind() == var_expr::prolog_var)
+      varExpr->set_var_info(vi);
+  }
+  else
   {
-    throw XQUERY_EXCEPTION_VAR(err,
-    ERROR_PARAMS(qname->getStringValue()), ERROR_LOC(loc));
+    if (!theVariablesMap->insert(qname, vi))
+    {
+      throw XQUERY_EXCEPTION_VAR(err,
+      ERROR_PARAMS(qname->getStringValue()), ERROR_LOC(loc));
+    }
   }
 }
 

=== modified file 'test/rbkt/Queries/CMakeLists.txt'
--- test/rbkt/Queries/CMakeLists.txt	2012-08-14 11:13:50 +0000
+++ test/rbkt/Queries/CMakeLists.txt	2012-08-16 18:30:28 +0000
@@ -555,10 +555,7 @@
 EXPECTED_FAILURE(test/rbkt/zorba/reference/reference_5 868640)
 
 # external variable default expected failures
-EXPECTED_FAILURE(test/rbkt/zorba/ext_var/w3c/extvardef-010 900688) # forward references not implemented
-EXPECTED_FAILURE(test/rbkt/zorba/ext_var/w3c/extvardef-011 900688) # forward references not implemented -> cycles cannot be detected
 EXPECTED_FAILURE(test/rbkt/zorba/ext_var/w3c/extvardef-014 923672) # not possible to set context item for rbkt tests
-EXPECTED_FAILURE(test/rbkt/zorba/ext_var/w3c/extvardef-022 900688) # forward references not implemented
 EXPECTED_FAILURE(test/rbkt/zorba/ext_var/w3c/extvardef-015 923686)
 EXPECTED_FAILURE(test/rbkt/zorba/ext_var/w3c/extvardef-016 923686)
 

=== modified file 'test/rbkt/Queries/zorba/ext_var/w3c/extvardef-011.xq'
--- test/rbkt/Queries/zorba/ext_var/w3c/extvardef-011.xq	2011-12-06 15:13:50 +0000
+++ test/rbkt/Queries/zorba/ext_var/w3c/extvardef-011.xq	2012-08-16 18:30:28 +0000
@@ -1,3 +1,4 @@
 declare variable $a := $x;
 declare variable $x external := $a + $b;
+declare variable $b := 1;
 $x

=== modified file 'test/rbkt/Queries/zorba/ext_var/w3c/extvardef-014.xq'
--- test/rbkt/Queries/zorba/ext_var/w3c/extvardef-014.xq	2011-12-06 15:13:50 +0000
+++ test/rbkt/Queries/zorba/ext_var/w3c/extvardef-014.xq	2012-08-16 18:30:28 +0000
@@ -1,3 +1,4 @@
 declare variable $x external := /works/employee[@name eq "Jane Doe 1"];
+
 fn:count($x)
 

=== modified file 'test/rbkt/Queries/zorba/ext_var/w3c/extvardef-015.xq'
--- test/rbkt/Queries/zorba/ext_var/w3c/extvardef-015.xq	2012-01-30 11:27:45 +0000
+++ test/rbkt/Queries/zorba/ext_var/w3c/extvardef-015.xq	2012-08-16 18:30:28 +0000
@@ -1,4 +1,7 @@
 declare variable $y := (<a>1</a>,<a>2</a>,<a>3</a>,<a>4</a>,<a>5</a>,<a>6</a>,<a>7</a>,<a>8</a>,<a>9</a>,<a>10</a>);
+
 declare context item := $y[3];
+
 declare variable $x external := fn:position();
+
 $x

=== modified file 'test/rbkt/Queries/zorba/ext_var/w3c/extvardef-016.xq'
--- test/rbkt/Queries/zorba/ext_var/w3c/extvardef-016.xq	2012-01-30 11:27:45 +0000
+++ test/rbkt/Queries/zorba/ext_var/w3c/extvardef-016.xq	2012-08-16 18:30:28 +0000
@@ -1,4 +1,7 @@
 declare variable $y := (<a>1</a>,<a>2</a>,<a>3</a>,<a>4</a>,<a>5</a>,<a>6</a>,<a>7</a>,<a>8</a>,<a>9</a>,<a>10</a>);
+
 declare context item := $y;
+
 declare variable $x external := fn:last();
+
 $x

=== modified file 'test/rbkt/Queries/zorba/ext_var/w3c/extvardef-022.xq'
--- test/rbkt/Queries/zorba/ext_var/w3c/extvardef-022.xq	2011-12-06 15:13:50 +0000
+++ test/rbkt/Queries/zorba/ext_var/w3c/extvardef-022.xq	2012-08-16 18:30:28 +0000
@@ -1,5 +1,8 @@
-declare function local:foo() {
+declare function local:foo() 
+{
   $x
 };
+
 declare variable $x external := 5;
-$y instance of xs:decimal
+
+local:foo()


Follow ups