zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #15645
[Merge] lp:~zorba-coders/zorba/markos-scratch into lp:zorba
Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/markos-scratch into lp:zorba.
Commit message:
further optimizations of the FoldConsts and EliminateUnusedLetVars rules
Requested reviews:
Markos Zaharioudakis (markos-za)
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/markos-scratch/+merge/131673
further optimizations of the FoldConsts and EliminateUnusedLetVars rules
--
https://code.launchpad.net/~zorba-coders/zorba/markos-scratch/+merge/131673
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog 2012-10-25 00:18:28 +0000
+++ ChangeLog 2012-10-26 18:28:41 +0000
@@ -7,8 +7,7 @@
* (bug #1039284) Implemented jn:json-doc().
Optimizations:
- * Optimized the MarkExpr and EliminateFlworVariables rules of the optimizer
- * Optimized the MarkFreeVars optimizer rule
+ * Various optimizations in the implementation of the optimizer rules.
Bug Fixes/Other Changes:
* Change XQXQ (XQuery-for-XQuery) module now part of Zorba core
=== modified file 'src/common/shared_types.h'
--- src/common/shared_types.h 2012-09-19 21:16:15 +0000
+++ src/common/shared_types.h 2012-10-26 18:28:41 +0000
@@ -96,8 +96,10 @@
class var_expr;
class flwor_clause;
class forletwin_clause;
-class for_clause;
-class let_clause;
+class forlet_clause;
+
+typedef forlet_clause for_clause;
+typedef forlet_clause let_clause;
class ItemVariableIterator;
typedef rchandle<ItemVariableIterator> ItemVariableIterator_t;
=== modified file 'src/compiler/codegen/plan_visitor.cpp'
--- src/compiler/codegen/plan_visitor.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/codegen/plan_visitor.cpp 2012-10-26 18:28:41 +0000
@@ -897,7 +897,7 @@
{
++numForClauses;
- const for_clause* fc = static_cast<const for_clause*>(c);
+ const forlet_clause* fc = static_cast<const forlet_clause*>(c);
if (fc->get_expr()->is_sequential())
{
@@ -910,7 +910,7 @@
}
else if (c->get_kind() == flwor_clause::let_clause)
{
- const let_clause* lc = static_cast<const let_clause*>(c);
+ const forlet_clause* lc = static_cast<const forlet_clause*>(c);
if (lc->get_expr()->is_sequential())
{
@@ -1061,20 +1061,12 @@
{
case flwor_clause::for_clause:
- {
- visit_flwor_clause(c, isGeneral);
-
- const for_clause* fc = reinterpret_cast<const for_clause*>(c);
- fc->get_expr()->accept(*this);
- break;
- }
-
case flwor_clause::let_clause:
{
visit_flwor_clause(c, isGeneral);
- const for_clause* fc = reinterpret_cast<const for_clause*>(c);
- fc->get_expr()->accept(*this);
+ const forlet_clause* flc = reinterpret_cast<const forlet_clause*>(c);
+ flc->get_expr()->accept(*this);
break;
}
@@ -1860,10 +1852,19 @@
std::vector<PlanIter_t>& posVarRefs =
clauseVarMap->theVarRebinds[1]->theOutputVarRefs;
- forletClauses.push_back(flwor::ForLetClause(var->get_name(),
- varRefs,
- posVarRefs,
- domainIter));
+ if (!posVarRefs.empty())
+ {
+ forletClauses.push_back(flwor::ForLetClause(var->get_name(),
+ varRefs,
+ posVarRefs,
+ domainIter));
+ }
+ else
+ {
+ forletClauses.push_back(flwor::ForLetClause(var->get_name(),
+ varRefs,
+ domainIter));
+ }
}
else
{
=== modified file 'src/compiler/expression/expr_base.cpp'
--- src/compiler/expression/expr_base.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_base.cpp 2012-10-26 18:28:41 +0000
@@ -315,10 +315,18 @@
setIgnoresDuplicateNodes(ANNOTATION_UNKNOWN);
if (getNonDiscardable() != ANNOTATION_TRUE_FIXED)
- setNonDiscardable(ANNOTATION_UNKNOWN);
+ setNonDiscardable(ANNOTATION_FALSE);
if (getUnfoldable() != ANNOTATION_TRUE_FIXED)
- setUnfoldable(ANNOTATION_UNKNOWN);
+ setUnfoldable(ANNOTATION_FALSE);
+
+ setContainsRecursiveCall(ANNOTATION_FALSE);
+
+ if (getConstructsNodes() != ANNOTATION_TRUE_FIXED)
+ setConstructsNodes(ANNOTATION_FALSE);
+
+ if (getDereferencesNodes() != ANNOTATION_TRUE_FIXED)
+ setDereferencesNodes(ANNOTATION_FALSE);
//theFlags1 = 0;
//setNonDiscardable(ANNOTATION_FALSE);
@@ -897,7 +905,7 @@
if (found)
break;
- const for_clause* fc = static_cast<const for_clause*>(clause);
+ const forlet_clause* fc = static_cast<const forlet_clause*>(clause);
if (fc->get_expr()->is_map_internal(e, found) && found)
{
@@ -915,7 +923,7 @@
if (found)
break;
- const let_clause* lc = static_cast<const let_clause*>(clause);
+ const forlet_clause* lc = static_cast<const forlet_clause*>(clause);
if (lc->get_expr()->contains_expr(e))
return false;
=== modified file 'src/compiler/expression/expr_base.h'
--- src/compiler/expression/expr_base.h 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_base.h 2012-10-26 18:28:41 +0000
@@ -126,8 +126,7 @@
{
friend class ExprIterator;
friend class forletwin_clause;
- friend class for_clause;
- friend class let_clause;
+ friend class forlet_clause;
friend class where_clause;
friend class function_trace_expr;
=== modified file 'src/compiler/expression/expr_manager.cpp'
--- src/compiler/expression/expr_manager.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_manager.cpp 2012-10-26 18:28:41 +0000
@@ -885,7 +885,7 @@
////////////////////////////////////////////////////////////////////////////////
-for_clause* ExprManager::create_for_clause(
+forlet_clause* ExprManager::create_for_clause(
static_context* sctx,
const QueryLoc& loc,
var_expr* varExpr,
@@ -894,19 +894,26 @@
var_expr* scoreVarExpr,
bool isOuter)
{
- CREATE_AND_RETURN(for_clause,
- sctx, theCCB, loc, varExpr, domainExpr, posVarExpr, scoreVarExpr, isOuter);
+ CREATE_AND_RETURN(forlet_clause,
+ sctx, theCCB, loc,
+ flwor_clause::for_clause,
+ varExpr, domainExpr, posVarExpr, scoreVarExpr,
+ isOuter, false);
}
-let_clause* ExprManager::create_let_clause(
+forlet_clause* ExprManager::create_let_clause(
static_context* sctx,
const QueryLoc& loc,
var_expr* varExpr,
expr* domainExpr,
bool lazy)
{
- CREATE_AND_RETURN(let_clause, sctx, theCCB, loc, varExpr, domainExpr, lazy);
+ CREATE_AND_RETURN(forlet_clause,
+ sctx, theCCB, loc,
+ flwor_clause::let_clause,
+ varExpr, domainExpr, NULL, NULL,
+ false, lazy);
}
@@ -921,7 +928,9 @@
bool lazy)
{
CREATE_AND_RETURN(window_clause,
- sctx, theCCB, loc, winKind, varExpr, domainExpr, winStart, winStop, lazy);
+ sctx, theCCB, loc,
+ winKind, varExpr, domainExpr, winStart, winStop,
+ lazy);
}
=== modified file 'src/compiler/expression/expr_manager.h'
--- src/compiler/expression/expr_manager.h 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_manager.h 2012-10-26 18:28:41 +0000
@@ -39,6 +39,7 @@
class catch_clause;
class pragma;
class flwor_clause;
+class forlet_clause;
class flwor_wincond;
class copy_clause;
class window_clause;
@@ -540,7 +541,7 @@
////////////////////////////////////////////////////////////////////////////////
- for_clause* create_for_clause(
+ forlet_clause* create_for_clause(
static_context* sctx,
const QueryLoc& loc,
var_expr* varExpr,
@@ -549,7 +550,7 @@
var_expr* scoreVarExpr = NULL,
bool isOuter = false);
- let_clause* create_let_clause(
+ forlet_clause* create_let_clause(
static_context* sctx,
const QueryLoc& loc,
var_expr* varExpr,
=== modified file 'src/compiler/expression/expr_put.cpp'
--- src/compiler/expression/expr_put.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/expr_put.cpp 2012-10-26 18:28:41 +0000
@@ -204,61 +204,37 @@
ostream& for_clause::put(ostream& os) const
{
-#if VERBOSE
- BEGIN_PUT( FOR );
-
- theVarExpr->put(os);
- PUT_SUB( "AT", thePosVarExpr );
- PUT_SUB( "SCORE", theScoreVarExpr );
-
- PUT_SUB("IN", theDomainExpr);
-
-#else
- os << indent << "FOR" << expr_addr(this) << " ";
-
- put_qname(theVarExpr->get_name(), os);
-
- os << expr_addr(theVarExpr);
-
- if (thePosVarExpr != NULL)
- {
- os << " AT ";
- put_qname(thePosVarExpr->get_name(), os);
- os << expr_addr(thePosVarExpr);
- }
- os << endl << indent << "[\n" << inc_indent;
-
- theDomainExpr->put(os);
-#endif
-
- END_PUT();
-}
-
-
-ostream& let_clause::put(ostream& os) const
-{
-#if VERBOSE
- BEGIN_PUT(LET);
-
- theVarExpr->put(os);
- PUT_SUB("SCORE", theScoreVarExpr);
-
- PUT_SUB(":=", theDomainExpr);
-
-#else
- os << indent << "LET" << expr_addr(this) << " ";
-
- put_qname(theVarExpr->get_name(), os);
-
- os << expr_addr(theVarExpr);
-
- os << endl << indent << "[\n" << inc_indent;
-
- theDomainExpr->put(os);
-#endif
-
- END_PUT();
-}
+ if (theKind == flwor_clause::for_clause)
+ {
+ os << indent << "FOR" << expr_addr(this) << " ";
+
+ put_qname(theVarExpr->get_name(), os);
+
+ os << expr_addr(theVarExpr);
+
+ if (thePosVarExpr != NULL)
+ {
+ os << " AT ";
+ put_qname(thePosVarExpr->get_name(), os);
+ os << expr_addr(thePosVarExpr);
+ }
+ }
+ else
+ {
+ os << indent << "LET" << expr_addr(this) << " ";
+
+ put_qname(theVarExpr->get_name(), os);
+
+ os << expr_addr(theVarExpr);
+ }
+
+ os << endl << indent << "[\n" << inc_indent;
+
+ theDomainExpr->put(os);
+
+ END_PUT();
+}
+
ostream& window_clause::put(ostream& os) const
{
=== modified file 'src/compiler/expression/flwor_expr.cpp'
--- src/compiler/expression/flwor_expr.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/flwor_expr.cpp 2012-10-26 18:28:41 +0000
@@ -122,20 +122,23 @@
/*******************************************************************************
********************************************************************************/
-for_clause::for_clause(
+forlet_clause::forlet_clause(
static_context* sctx,
CompilerCB* ccb,
const QueryLoc& loc,
+ flwor_clause::ClauseKind kind,
var_expr* varExpr,
expr* domainExpr,
var_expr* posVarExpr,
var_expr* scoreVarExpr,
- bool isAllowingEmpty)
+ bool isAllowingEmpty,
+ bool lazy)
:
- forletwin_clause(sctx, ccb, loc, flwor_clause::for_clause, varExpr, domainExpr),
+ forletwin_clause(sctx, ccb, loc, kind, varExpr, domainExpr),
thePosVarExpr(posVarExpr),
theScoreVarExpr(scoreVarExpr),
- theAllowingEmpty(isAllowingEmpty)
+ theAllowingEmpty(isAllowingEmpty),
+ theLazyEval(lazy)
{
if (thePosVarExpr != NULL)
thePosVarExpr->set_flwor_clause(this);
@@ -149,9 +152,10 @@
TypeManager* tm = sctx->get_typemanager();
xqtref_t declaredType = varExpr->get_type();
+
if (declaredType != NULL)
{
- if (declaredType->is_empty())
+ if (kind == flwor_clause::for_clause && declaredType->is_empty())
{
RAISE_ERROR(err::XPTY0004, loc,
ERROR_PARAMS(ZED(BadType_23o), "empty-sequence"));
@@ -159,20 +163,19 @@
xqtref_t domainType = domainExpr->get_return_type();
- if (!TypeOps::is_subtype(tm, *rtm.ITEM_TYPE_STAR, *declaredType, loc))
+ if (!TypeOps::is_equal(tm, *rtm.ITEM_TYPE_STAR, *declaredType, loc))
{
- declaredType = tm->create_type(*declaredType, TypeConstants::QUANT_STAR);
+ if (kind == flwor_clause::for_clause)
+ declaredType = tm->create_type(*declaredType, domainType->get_quantifier());
if (!TypeOps::is_subtype(tm, *domainType, *declaredType, loc))
{
xqtref_t varType = TypeOps::intersect_type(*domainType, *declaredType, tm);
+
if (TypeOps::is_equal(tm, *varType, *rtm.NONE_TYPE, loc))
{
RAISE_ERROR(err::XPTY0004, loc,
- ERROR_PARAMS(ZED(BadType_23o),
- *domainType,
- ZED(NoTreatAs_4),
- *declaredType));
+ ERROR_PARAMS(ZED(BadType_23o), *domainType, ZED(NoTreatAs_4), *declaredType));
}
domainExpr = theCCB->theEM->
@@ -191,7 +194,7 @@
}
-for_clause::~for_clause()
+forlet_clause::~forlet_clause()
{
if (thePosVarExpr != NULL)
thePosVarExpr->set_flwor_clause(NULL);
@@ -201,19 +204,19 @@
}
-var_expr* for_clause::get_pos_var() const
+var_expr* forlet_clause::get_pos_var() const
{
return thePosVarExpr;
}
-var_expr* for_clause::get_score_var() const
+var_expr* forlet_clause::get_score_var() const
{
return theScoreVarExpr;
}
-void for_clause::set_pos_var(var_expr* v)
+void forlet_clause::set_pos_var(var_expr* v)
{
thePosVarExpr = v;
if (thePosVarExpr != NULL)
@@ -221,7 +224,7 @@
}
-void for_clause::set_score_var(var_expr* v)
+void forlet_clause::set_score_var(var_expr* v)
{
theScoreVarExpr = v;
if (theScoreVarExpr != NULL)
@@ -229,7 +232,7 @@
}
-flwor_clause* for_clause::clone(user_function* udf, expr::substitution_t& subst) const
+flwor_clause* forlet_clause::clone(user_function* udf, expr::substitution_t& subst) const
{
expr* domainCopy = theDomainExpr->clone(udf, subst);
@@ -245,123 +248,31 @@
}
var_expr* scorevarCopy = NULL;
- var_expr* score_var_ptr = theScoreVarExpr;
- if (score_var_ptr)
- {
- scorevarCopy = theCCB->theEM->create_var_expr(udf, *score_var_ptr);
- subst[score_var_ptr] = scorevarCopy;
- }
-
- return theCCB->theEM->create_for_clause(theContext,
- get_loc(),
- varCopy,
- domainCopy,
- posvarCopy,
- scorevarCopy,
- theAllowingEmpty);
-}
-
-
-/*******************************************************************************
-
-********************************************************************************/
-let_clause::let_clause(
- static_context* sctx,
- CompilerCB* ccb,
- const QueryLoc& loc,
- var_expr* varExpr,
- expr* domainExpr,
- bool lazy)
- :
- forletwin_clause(sctx, ccb, loc, flwor_clause::let_clause, varExpr, domainExpr),
- theScoreVarExpr(NULL),
- theLazyEval(lazy)
-{
- if (theScoreVarExpr != NULL)
- theScoreVarExpr->set_flwor_clause(this);
-
- if (varExpr != NULL && sctx != NULL)
- {
- RootTypeManager& rtm = GENV_TYPESYSTEM;
- TypeManager* tm = sctx->get_typemanager();
-
- xqtref_t declaredType = varExpr->get_type();
-
- if (declaredType != NULL)
- {
- xqtref_t domainType = domainExpr->get_return_type();
-
- if (!TypeOps::is_subtype(tm, *rtm.ITEM_TYPE_STAR, *declaredType, loc) &&
- !TypeOps::is_subtype(tm, *domainType, *declaredType, loc))
- {
- xqtref_t varType = TypeOps::intersect_type(*domainType, *declaredType, tm);
-
- if (TypeOps::is_equal(tm, *varType, *rtm.NONE_TYPE, loc))
- {
- RAISE_ERROR(err::XPTY0004, loc,
- ERROR_PARAMS(ZED(BadType_23o), *domainType, ZED(NoTreatAs_4), *declaredType));
- }
-
- domainExpr = theCCB->theEM->
- create_treat_expr(sctx,
- domainExpr->get_udf(),
- loc,
- domainExpr,
- declaredType,
- TREAT_TYPE_MATCH);
-
- set_expr(domainExpr);
- }
- }
- }
-}
-
-
-let_clause::~let_clause()
-{
- if (theScoreVarExpr != NULL)
- theScoreVarExpr->set_flwor_clause(NULL);
-}
-
-
-var_expr* let_clause::get_score_var() const
-{
- return theScoreVarExpr;
-}
-
-
-void let_clause::set_score_var(var_expr* v)
-{
- theScoreVarExpr = v;
- if (theScoreVarExpr != NULL)
- theScoreVarExpr->set_flwor_clause(this);
-}
-
-
-flwor_clause* let_clause::clone(user_function* udf, expr::substitution_t& subst) const
-{
- expr* domainCopy = theDomainExpr->clone(udf, subst);
-
- var_expr* varCopy = theCCB->theEM->create_var_expr(udf, *theVarExpr);
- subst[theVarExpr] = varCopy;
-
-#if 0
- var_expr* scorevarCopy = NULL;
- var_expr* score_var_ptr = theScoreVarExpr;
- if (score_var_ptr)
- {
- scorevarCopy = theCCB->theEM->create_var_expr(*score_var_ptr);
- subst->get(score_var_ptr) = scorevarCopy;
- }
-#endif
-
- return theCCB->theEM->create_let_clause(theContext,
- get_loc(),
- varCopy,
- domainCopy,
- theLazyEval);
-}
-
+ if (theScoreVarExpr)
+ {
+ scorevarCopy = theCCB->theEM->create_var_expr(udf, *theScoreVarExpr);
+ subst[theScoreVarExpr] = scorevarCopy;
+ }
+
+ if (theKind == flwor_clause::for_clause)
+ {
+ return theCCB->theEM->create_for_clause(theContext,
+ get_loc(),
+ varCopy,
+ domainCopy,
+ posvarCopy,
+ scorevarCopy,
+ theAllowingEmpty);
+ }
+ else
+ {
+ return theCCB->theEM->create_let_clause(theContext,
+ get_loc(),
+ varCopy,
+ domainCopy,
+ theLazyEval);
+ }
+}
/*******************************************************************************
=== modified file 'src/compiler/expression/flwor_expr.h'
--- src/compiler/expression/flwor_expr.h 2012-10-24 11:32:56 +0000
+++ src/compiler/expression/flwor_expr.h 2012-10-26 18:28:41 +0000
@@ -30,9 +30,6 @@
class ExprManager;
class order_modifier;
-class flwor_clause;
-class for_clause;
-class let_clause;
class window_clause;
class flwor_wincond;
class orderby_clause;
@@ -96,6 +93,8 @@
ClauseKind get_kind() const { return theKind; }
+ void set_kind(ClauseKind k) { theKind = k; }
+
flwor_expr* get_flwor_expr() const { return theFlworExpr; }
virtual void set_expr(expr* v) { }
@@ -172,7 +171,7 @@
/***************************************************************************//**
********************************************************************************/
-class for_clause : public forletwin_clause
+class forlet_clause : public forletwin_clause
{
friend class flwor_expr;
friend class ExprManager;
@@ -182,25 +181,32 @@
var_expr * thePosVarExpr;
var_expr * theScoreVarExpr;
bool theAllowingEmpty;
+ bool theLazyEval;
protected:
- for_clause(
+ forlet_clause(
static_context* sctx,
CompilerCB* ccb,
const QueryLoc& loc,
+ flwor_clause::ClauseKind kind,
var_expr* varExpr,
expr* domainExpr,
- var_expr* posVarExpr = NULL,
- var_expr* scoreVarExpr = NULL,
- bool isOuter = false);
+ var_expr* posVarExpr,
+ var_expr* scoreVarExpr,
+ bool isOuter,
+ bool lazy);
public:
- ~for_clause();
+ ~forlet_clause();
bool is_allowing_empty() const { return theAllowingEmpty; }
void set_allowing_empty(bool allowing_empty) { theAllowingEmpty = allowing_empty; }
+ void setLazyEval(bool v) { theLazyEval = v; }
+
+ bool lazyEval() const { return theLazyEval; }
+
var_expr* get_pos_var() const;
var_expr* get_score_var() const;
@@ -216,47 +222,6 @@
/***************************************************************************//**
- theScoreVarExpr :
- theLazyEval : Whether the window var can be materilized lazily or not.
-********************************************************************************/
-class let_clause : public forletwin_clause
-{
- friend class expr;
- friend class flwor_expr;
- friend class ExprManager;
- friend class ExprIterator;
-
-protected:
- var_expr * theScoreVarExpr;
- bool theLazyEval;
-
-protected:
- let_clause(
- static_context* sctx,
- CompilerCB* ccb,
- const QueryLoc& loc,
- var_expr* varExpr,
- expr* domainExpr,
- bool lazy = false);
-
-public:
- ~let_clause();
-
- var_expr* get_score_var() const;
-
- void set_score_var(var_expr* v);
-
- void setLazyEval(bool v) { theLazyEval = v; }
-
- bool lazyEval() const { return theLazyEval; }
-
- flwor_clause* clone(user_function* udf, expr::substitution_t& substitution) const;
-
- std::ostream& put(std::ostream&) const;
-};
-
-
-/***************************************************************************//**
theWindowKind :
theWinStartCond :
theWinStopCond :
=== modified file 'src/compiler/expression/var_expr.cpp'
--- src/compiler/expression/var_expr.cpp 2012-10-19 20:42:38 +0000
+++ src/compiler/expression/var_expr.cpp 2012-10-26 18:28:41 +0000
@@ -284,9 +284,12 @@
/*******************************************************************************
********************************************************************************/
-for_clause* var_expr::get_for_clause() const
+forlet_clause* var_expr::get_forlet_clause() const
{
- return dynamic_cast<for_clause*>(theFlworClause);
+ assert(theFlworClause->get_kind() == flwor_clause::for_clause ||
+ theFlworClause->get_kind() == flwor_clause::let_clause);
+
+ return static_cast<forlet_clause*>(theFlworClause);
}
=== modified file 'src/compiler/expression/var_expr.h'
--- src/compiler/expression/var_expr.h 2012-10-09 14:06:08 +0000
+++ src/compiler/expression/var_expr.h 2012-10-26 18:28:41 +0000
@@ -24,7 +24,7 @@
class flwor_clause;
class forletwin_clause;
-class for_clause;
+class forlet_clause;
class copy_clause;
class var_expr;
class VarInfo;
@@ -230,7 +230,7 @@
forletwin_clause* get_forletwin_clause() const;
- for_clause* get_for_clause() const;
+ forlet_clause* get_forlet_clause() const;
copy_clause* get_copy_clause() const { return theCopyClause; }
=== modified file 'src/compiler/rewriter/framework/rewriter_context.cpp'
--- src/compiler/rewriter/framework/rewriter_context.cpp 2012-10-10 13:05:50 +0000
+++ src/compiler/rewriter/framework/rewriter_context.cpp 2012-10-26 18:28:41 +0000
@@ -72,7 +72,7 @@
}
-expr* RewriterContext::getRoot()
+expr* RewriterContext::getRoot() const
{
return theRoot;
}
=== modified file 'src/compiler/rewriter/framework/rewriter_context.h'
--- src/compiler/rewriter/framework/rewriter_context.h 2012-10-10 13:05:50 +0000
+++ src/compiler/rewriter/framework/rewriter_context.h 2012-10-26 18:28:41 +0000
@@ -107,7 +107,7 @@
CompilerCB* getCompilerCB() const { return theCCB; }
- expr* getRoot();
+ expr* getRoot() const;
void setRoot(expr* root);
=== modified file 'src/compiler/rewriter/rewriters/default_optimizer.cpp'
--- src/compiler/rewriter/rewriters/default_optimizer.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rewriters/default_optimizer.cpp 2012-10-26 18:28:41 +0000
@@ -38,7 +38,7 @@
{
ADD_RULE(MarkExprs);
ADD_RULE(MarkFreeVars);
- ADD_RULE(FoldConst(false));
+ ADD_RULE(FoldConst);
ADD_RULE(PartialEval);
ADD_RULE(RefactorPredFLWOR);
ADD_RULE(EliminateUnusedLetVars);
=== modified file 'src/compiler/rewriter/rules/flwor_rules.cpp'
--- src/compiler/rewriter/rules/flwor_rules.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/flwor_rules.cpp 2012-10-26 18:28:41 +0000
@@ -43,16 +43,6 @@
static bool is_trivial_expr(const expr*);
-static bool
-safe_to_fold_single_use(
- var_expr*,
- TypeConstants::quantifier_t,
- const flwor_expr&,
- const std::vector<const expr*>&);
-
-static bool
-var_in_try_or_loop(const var_expr*, const expr*, bool, bool, bool&);
-
static void
rewrite_positional_pred(
RewriterContext&,
@@ -181,6 +171,24 @@
/*******************************************************************************
+ This is actually 4 rules bundled together:
+
+ 1. trivial-FLWOR-elimination :
+
+ "for $x in E return $x" --> "E"
+ "let $x := E return $x" --> "E"
+
+
+ 2. where-clause-to-if-then-else :
+
+ "for $x in ... where E ... return ...", and E doesn't depend on FLWOR vars -->
+ "if E then flwor else ()", where flwor is the original flwor expr without the
+ where clause.
+
+
+ 3. LET-FOR-variable-folding-or-elimination :
+
+ 4. non-grouping-variable-elimination :
*******************************************************************************/
RULE_REWRITE_PRE(EliminateUnusedLetVars)
@@ -195,48 +203,42 @@
assert(udf == rCtx.theUDF);
- flwor_expr* flworp = static_cast<flwor_expr *>(node);
- flwor_expr& flwor = *flworp;
+ theFlwor = static_cast<flwor_expr *>(node);
- csize numClauses = flwor.num_clauses();
+ csize numClauses = theFlwor->num_clauses();
// numClauses may be 0 in the case this flwor became a common sub-expression
// due to var-inlining inside an if-then-else expr (see test
// zorba/optim/flwor_vars_02.xq)
if (numClauses == 0)
{
- return flwor.get_return_expr();
+ return theFlwor->get_return_expr();
}
- // "for $x in E return $x" --> "E"
- // "let $x := E return $x" --> "E"
- // Single windowing clauses are left alone
+ // 1. trivial-FLWOR-elimination
if (numClauses == 1 &&
- flwor.get_clause(0)->get_kind() != flwor_clause::window_clause)
+ theFlwor->get_clause(0)->get_kind() != flwor_clause::window_clause)
{
- assert(flwor.get_clause(0)->get_kind() == flwor_clause::for_clause ||
- flwor.get_clause(0)->get_kind() == flwor_clause::let_clause);
+ assert(theFlwor->get_clause(0)->get_kind() == flwor_clause::for_clause ||
+ theFlwor->get_clause(0)->get_kind() == flwor_clause::let_clause);
const forletwin_clause* flwc =
- static_cast<const forletwin_clause *>(flwor.get_clause(0));
+ static_cast<const forletwin_clause *>(theFlwor->get_clause(0));
- if (flwor.get_return_expr()->get_var() == flwc->get_var())
+ if (theFlwor->get_return_expr()->get_var() == flwc->get_var())
{
return flwc->get_expr();
}
}
- // "for $x in ... where E ... return ...", and E doesn't depend on FLWOR vars
- // --> "if E then flwor else ()", where flwor is the original flwor expr
- // without the where clause.
- if (!flwor.has_sequential_clauses())
+ // 2. where-clause-to-if-then-else
+ if (!theFlwor->has_sequential_clauses())
{
- expr::FreeVars myVars;
expr* whereExpr = NULL;
for (csize i = 0; i < numClauses; ++i)
{
- flwor_clause* clause = flwor.get_clause(i);
+ flwor_clause* clause = theFlwor->get_clause(i);
if (clause->get_kind() == flwor_clause::where_clause)
{
@@ -249,7 +251,7 @@
for (; ite != end; ++ite)
{
flwor_clause* vc = (*ite)->get_flwor_clause();
- if (vc != NULL && vc->get_flwor_expr() == flworp)
+ if (vc != NULL && vc->get_flwor_expr() == theFlwor)
break;
++k;
@@ -257,14 +259,14 @@
if (k == whereVars.size())
{
- flwor.remove_clause(i);
+ theFlwor->remove_clause(i);
if_expr* ifExpr = rCtx.theEM->
create_if_expr(sctx,
udf,
loc,
whereExpr,
- flworp,
+ theFlwor,
rCtx.theEM->create_seq(sctx, udf, loc));
fix_if_annotations(ifExpr);
@@ -285,11 +287,13 @@
// (d) Remove any unused non-group variables from GROUP BY clauses.
for (csize i = 0; i < numClauses; ++i)
{
- bool substitute = false;
-
- flwor_clause* c = flwor.get_clause(i);
-
- if (c->get_kind() == flwor_clause::group_clause)
+ int isReferenced;
+
+ flwor_clause* c = theFlwor->get_clause(i);
+
+ switch (c->get_kind())
+ {
+ case flwor_clause::group_clause:
{
group_clause* gc = static_cast<group_clause *>(c);
@@ -299,7 +303,7 @@
for(; ite != end; ++ite)
{
var_expr* var = ite->second;
- int uses = expr_tools::count_variable_uses(&flwor, var, 1, NULL);
+ int uses = expr_tools::count_variable_uses(theFlwor, var, 1, NULL);
if (uses == 0 && !ite->first->isNonDiscardable())
{
@@ -308,8 +312,10 @@
end = gc->endNonGroupVars();
}
}
+
+ break;
}
- else if (c->get_kind() == flwor_clause::for_clause)
+ case flwor_clause::for_clause:
{
for_clause* fc = static_cast<for_clause *>(c);
@@ -321,7 +327,7 @@
var_expr* pvar = fc->get_pos_var();
if (pvar != NULL &&
- expr_tools::count_variable_uses(&flwor, pvar, 1, NULL) == 0)
+ expr_tools::count_variable_uses(theFlwor, pvar, 1, NULL) == 0)
{
fc->set_pos_var(NULL);
pvar = NULL;
@@ -352,132 +358,88 @@
expr* emptyExpr = rCtx.theEM->create_seq(sctx, udf, LOC(node));
MODIFY(subst_vars(rCtx, node, var, emptyExpr));
- substitute = true;
+
+ MODIFY(theFlwor->remove_clause(i));
+ --numClauses;
+ --i;
+
+ theFlwor->compute_return_type(false, NULL);
}
}
-
// FOR clause with cardinality 0 or 1
else
{
- if (pvar != NULL)
- {
- if (domainQuant == TypeConstants::QUANT_ONE ||
- ! fc->is_allowing_empty())
- {
- expr* constExpr = rCtx.theEM->
- create_const_expr(sctx, udf, loc, xs_integer::one());
-
- MODIFY(subst_vars(rCtx, node, pvar, constExpr));
- fc->set_pos_var(NULL);
- }
- }
-
- std::vector<const expr*> refpath(16);
- int uses = expr_tools::count_variable_uses(&flwor, var, 2, &refpath);
-
- if (uses > 1 &&
- is_trivial_expr(domainExpr) &&
- (domainQuant == TypeConstants::QUANT_ONE ||
- fc->is_allowing_empty()))
- {
- subst_vars(rCtx, node, var, domainExpr);
- substitute = true;
- }
- else if (uses == 1 &&
- (domainQuant == TypeConstants::QUANT_ONE || i == numClauses -1) &&
- ((is_trivial_expr(domainExpr) &&
- domainQuant == TypeConstants::QUANT_ONE) ||
- safe_to_fold_single_use(var, domainQuant, flwor, refpath)))
- {
- subst_vars(rCtx, node, var, domainExpr);
- substitute = true;
- }
- else if (uses == 0 &&
- !domainExpr->isNonDiscardable() &&
- (domainQuant == TypeConstants::QUANT_ONE ||
- fc->is_allowing_empty()))
- {
- substitute = true;
- }
- }
-
- if (substitute)
- {
- MODIFY(flwor.remove_clause(i));
- --numClauses;
- --i;
-
- flwor.compute_return_type(true, NULL);
- }
+ if (pvar != NULL &&
+ (domainQuant == TypeConstants::QUANT_ONE ||
+ ! fc->is_allowing_empty()))
+ {
+ expr* constExpr = rCtx.theEM->
+ create_const_expr(sctx, udf, loc, xs_integer::one());
+
+ MODIFY(subst_vars(rCtx, node, pvar, constExpr));
+ fc->set_pos_var(NULL);
+ }
+
+ if (safe_to_fold_var(i, isReferenced))
+ {
+ if (isReferenced != 0)
+ subst_vars(rCtx, node, var, domainExpr);
+
+ MODIFY(theFlwor->remove_clause(i));
+ --numClauses;
+ --i;
+
+#if 0
+ std::cout << rCtx.theMessage << std::endl
+ << "After subst " << var << " :" << std::endl;
+ rCtx.getRoot()->put(std::cout) << std::endl;
+#endif
+ theFlwor->compute_return_type(false, NULL);
+ }
+ }
+
+ break;
}
- else if (c->get_kind() == flwor_clause::let_clause)
+ case flwor_clause::let_clause:
{
let_clause* lc = static_cast<let_clause *>(c);
-
+ var_expr* var = lc->get_var();
expr* domainExpr = lc->get_expr();
- xqtref_t domainType = domainExpr->get_return_type();
- TypeConstants::quantifier_t domainQuant = domainType->get_quantifier();
- var_expr* var = lc->get_var();
-
- if (domainExpr->is_sequential())
- continue;
-
- std::vector<const expr*> refpath(16);
- int uses = expr_tools::count_variable_uses(&flwor, var, 2, &refpath);
-
- if (uses > 1 && is_trivial_expr(domainExpr))
- {
- subst_vars(rCtx, node, var, domainExpr);
- substitute = true;
- }
- else if (uses == 1 &&
- (is_trivial_expr(domainExpr) ||
- safe_to_fold_single_use(var, TypeConstants::QUANT_ONE, flwor, refpath)))
- {
- subst_vars(rCtx, node, var, domainExpr);
- substitute = true;
- }
- else if (uses == 0 && !domainExpr->isNonDiscardable())
- {
- substitute = true;
+ TypeConstants::quantifier_t domainQuant =
+ domainExpr->get_return_type()->get_quantifier();
+
+ if (safe_to_fold_var(i, isReferenced))
+ {
+ if (isReferenced != 0)
+ subst_vars(rCtx, node, var, domainExpr);
+
+ MODIFY(theFlwor->remove_clause(i));
+ --numClauses;
+ --i;
+
#if 0
- rCtx.getCompilerCB()->theXQueryDiagnostics->add_warning(
- NEW_XQUERY_WARNING(zwarn::ZWST0001_UNUSED_VARIABLE,
- WARN_PARAMS(var->get_name()->getStringValue()),
- WARN_LOC(var->get_loc())));
+ std::cout << rCtx.theMessage << std::endl
+ << "After subst " << var << " :" << std::endl;
+ rCtx.getRoot()->put(std::cout) << std::endl;
#endif
}
-
- if (substitute)
- {
- MODIFY(flwor.remove_clause(i));
- --numClauses;
- --i;
- }
else if (domainQuant == TypeConstants::QUANT_ONE)
{
- MODIFY(flwor.remove_clause(i));
- const QueryLoc& loc = var->get_loc();
- var_expr* fvar = rCtx.theEM->
- create_var_expr(sctx, udf, loc, var_expr::for_var, var->get_name());
-
- fvar->getFreeVars().insert(fvar);
-
- for_clause* fc = rCtx.theEM->
- create_for_clause(sctx, loc, fvar, domainExpr);
-
- flwor.add_clause(i, fc);
-
- subst_vars(rCtx, node, var, fvar);
+ lc->set_kind(flwor_clause::for_clause);
+ var->set_kind(var_expr::for_var);
+ modified = true;
}
}
+ default:
+ break;
+ }
}
expr* whereCond = NULL;
- while (flwor.num_clauses() > 0)
+ while (theFlwor->num_clauses() > 0)
{
- flwor_clause* clause = flwor.get_clause(0);
+ flwor_clause* clause = theFlwor->get_clause(0);
if (clause->get_kind() == flwor_clause::for_clause ||
clause->get_kind() == flwor_clause::let_clause ||
@@ -502,7 +464,7 @@
let_clause* letClause = rCtx.theEM->
create_let_clause(sctx, gVar->get_loc(), gVar, inputExpr);
- flwor.add_clause(1, letClause);
+ theFlwor->add_clause(1, letClause);
}
const flwor_clause::rebind_list_t& ngVars = gc->get_nongrouping_vars();
@@ -518,10 +480,10 @@
let_clause* letClause = rCtx.theEM->
create_let_clause(sctx, ngVar->get_loc(), ngVar, inputExpr);
- flwor.add_clause(1, letClause);
+ theFlwor->add_clause(1, letClause);
}
- flwor.remove_clause(0);
+ theFlwor->remove_clause(0);
continue;
}
else if (clause->get_kind() == flwor_clause::where_clause)
@@ -553,28 +515,28 @@
}
//as soon as whereCond is not NULL we don't need to mark as modified
- flwor.remove_clause(0);
+ theFlwor->remove_clause(0);
continue;
}
else if (clause->get_kind() == flwor_clause::count_clause)
{
// since one value is still returned, count variables are changed to 1
subst_vars(rCtx,
- flworp,
+ theFlwor,
static_cast<count_clause*>(clause)->get_var(),
rCtx.theEM->create_const_expr(sctx, udf, loc, xs_integer::one()));
- flwor.remove_clause(0);
+ theFlwor->remove_clause(0);
continue;
}
else if (clause->get_kind() == flwor_clause::order_clause)
{
- flwor.remove_clause(0);
+ theFlwor->remove_clause(0);
continue;
}
else if (clause->get_kind() == flwor_clause::materialize_clause)
{
- flwor.remove_clause(0);
+ theFlwor->remove_clause(0);
continue;
}
else
@@ -585,7 +547,7 @@
if (whereCond != NULL)
{
- expr* result = (flwor.num_clauses() > 0 ? flworp : flwor.get_return_expr());
+ expr* result = (theFlwor->num_clauses() > 0 ? theFlwor : theFlwor->get_return_expr());
if_expr* ifExpr = rCtx.theEM->
create_if_expr(sctx,
@@ -600,8 +562,8 @@
return ifExpr;
}
- if (flwor.num_clauses() == 0)
- return flwor.get_return_expr();
+ if (theFlwor->num_clauses() == 0)
+ return theFlwor->get_return_expr();
return modified ? node : NULL;
}
@@ -613,43 +575,6 @@
}
-/******************************************************************************
-
-******************************************************************************/
-static bool is_trivial_expr(const expr* e)
-{
- switch (e->get_expr_kind())
- {
- case const_expr_kind:
- {
- return true;
- }
- case var_expr_kind:
- {
- const var_expr* ve = static_cast<const var_expr*>(e);
- enum var_expr::var_kind k = ve->get_kind();
-
- // NOTE: An arg var is not materialized, and as a result, it cannot be
- // referenced more than once or be refeneced inside a loop or try block.
- // Therefore, an arg var that appears as the domain expr of a LET var
- // cannot trivially substitute the LET var.
- if (k == var_expr::arg_var ||
- k == var_expr::local_var ||
- (k == var_expr::prolog_var && ve->is_mutable()))
- return false;
-
- return true;
- }
- case wrapper_expr_kind:
- {
- return is_trivial_expr(static_cast<const wrapper_expr*>(e)->get_input());
- }
- default:
- return false;
- }
-}
-
-
/*****************************************************************************
Check if it is OK to fold (inline) a FOR/LET var X that we know is referenced
only once withing its flwor expr.
@@ -659,86 +584,100 @@
For a FOR var, varQuant is the quantifier of the type of the domain expr.
It can be either QUANT_ONE or QUANT_QUESTION.
******************************************************************************/
-static bool safe_to_fold_single_use(
- var_expr* var,
- TypeConstants::quantifier_t varQuant,
- const flwor_expr& flwor,
- const std::vector<const expr*>& refpath)
+bool EliminateUnusedLetVars::safe_to_fold_var(csize varPos, int& numRefs)
{
- TypeManager* tm = var->get_type_manager();
-
- if (flwor.dereferencesNodes() && var->get_domain_expr()->constructsNodes())
+ TypeManager* tm = theFlwor->get_type_manager();
+
+ // if set to true, then it is unsafe to fold, but we may still be able to
+ // completely eliminate the var if it not referenced anywhere.
+ bool unsafe = false;
+
+ theRefPath.clear();
+ numRefs = 0;
+
+ forletwin_clause* varClause =
+ static_cast<forletwin_clause*>(theFlwor->get_clause(varPos));
+
+ var_expr* var = varClause->get_var();
+ expr* varDomExpr = varClause->get_expr();
+
+ bool isSafeVar =
+ (varClause->get_kind() == flwor_clause::let_clause ||
+ static_cast<for_clause*>(varClause)->is_allowing_empty() ||
+ varDomExpr->get_return_type()->get_quantifier() == TypeConstants::QUANT_ONE);
+
+ if (is_trivial_expr(varDomExpr))
+ {
+ numRefs = 1;
+ return isSafeVar;
+ }
+
+ if (varDomExpr->is_sequential())
return false;
- bool declared = false;
- expr* referencingExpr = NULL;
- csize numClauses = flwor.num_clauses();
-
- for (csize i = 0; i < numClauses && referencingExpr == NULL; ++i)
+ if (theFlwor->dereferencesNodes() && varDomExpr->constructsNodes())
+ unsafe = true;
+
+ csize numClauses = theFlwor->num_clauses();
+
+ for (csize i = varPos+1; i < numClauses; ++i)
{
- const flwor_clause* clause = flwor.get_clause(i);
+ const flwor_clause* clause = theFlwor->get_clause(i);
flwor_clause::ClauseKind kind = clause->get_kind();
+ std::vector<const expr*>* path = (numRefs > 0 ? NULL : &theRefPath);
+ int maxUses = 2 - numRefs;
+
switch (kind)
{
case flwor_clause::for_clause:
case flwor_clause::let_clause:
{
const forletwin_clause* flc = static_cast<const forletwin_clause *>(clause);
- var_expr* varExpr = flc->get_var();
expr* domExpr = flc->get_expr();
- if (! declared)
- {
- declared = (varExpr == var);
- continue;
- }
-
- assert(varQuant == TypeConstants::QUANT_ONE);
-
- if (domExpr->is_sequential())
- return false;
-
- // If X is referenced in the current FOR clause .....
- if (std::find(refpath.begin(), refpath.end(), domExpr) != refpath.end())
- {
- referencingExpr = domExpr;
- break;
- }
-
- // If X is referenced after this FOR clause. In this case, we don't want
- // to inline X because its domain expr will be computed once per iteration
- // instead of just once.
- if (kind == flwor_clause::for_clause &&
- domExpr->get_return_type()->max_card() >= 2)
- return false;
+ int uses = expr_tools::count_variable_uses(domExpr, var, maxUses, path);
+
+ if (uses > 0)
+ {
+ if (uses + numRefs > 1 || unsafe || !isSafeVar || domExpr->is_sequential())
+ return false;
+
+ numRefs = 1;
+ }
+ else if (numRefs == 0)
+ {
+ if (domExpr->is_sequential())
+ unsafe = true;
+
+ // If X is referenced after this FOR clause. In this case, we don't want
+ // to inline X because its domain expr will be computed once per iteration
+ // instead of just once.
+ if (kind == flwor_clause::for_clause &&
+ domExpr->get_return_type()->max_card() >= 2)
+ unsafe = true;
+ }
break;
}
case flwor_clause::where_clause:
{
- if (!declared)
- continue;
-
- assert(varQuant == TypeConstants::QUANT_ONE);
-
expr* whereExpr = static_cast<const where_clause*>(clause)->get_expr();
- if (std::find(refpath.begin(), refpath.end(), whereExpr) != refpath.end())
+ int uses = expr_tools::count_variable_uses(whereExpr, var, maxUses, path);
+
+ if (uses > 0)
{
- referencingExpr = whereExpr;
- break;
+ if (uses + numRefs > 1 || unsafe || !isSafeVar)
+ return false;
+
+ numRefs = 1;
}
break;
}
case flwor_clause::order_clause:
{
- if (!declared)
- continue;
-
- assert(varQuant == TypeConstants::QUANT_ONE);
-
const orderby_clause* oc = static_cast<const orderby_clause*>(clause);
std::vector<expr*>::const_iterator ite = oc->begin();
@@ -746,10 +685,14 @@
for (; ite != end; ++ite)
{
- if (std::find(refpath.begin(), refpath.end(), *ite) != refpath.end())
+ int uses = expr_tools::count_variable_uses(*ite, var, maxUses, path);
+
+ if (uses > 0)
{
- referencingExpr = *ite;
- break;
+ if (uses + numRefs > 1 || unsafe || !isSafeVar)
+ return false;
+
+ numRefs = 1;
}
}
@@ -757,11 +700,6 @@
}
case flwor_clause::group_clause:
{
- if (!declared)
- continue;
-
- assert(varQuant == TypeConstants::QUANT_ONE);
-
const group_clause* gc = static_cast<const group_clause*>(clause);
flwor_clause::rebind_list_t::const_iterator ite = gc->beginGroupVars();
@@ -770,10 +708,15 @@
for (; ite != end; ++ite)
{
expr* inputExpr = ite->first;
- if (std::find(refpath.begin(), refpath.end(), inputExpr) != refpath.end())
+
+ int uses = expr_tools::count_variable_uses(inputExpr, var, maxUses, path);
+
+ if (uses > 0)
{
- referencingExpr = inputExpr;
- break;
+ if (uses + numRefs > 1 || unsafe || !isSafeVar)
+ return false;
+
+ numRefs = 1;
}
}
@@ -783,10 +726,15 @@
for (; ite != end; ++ite)
{
expr* inputExpr = ite->first;
- if (std::find(refpath.begin(), refpath.end(), inputExpr) != refpath.end())
+
+ int uses = expr_tools::count_variable_uses(inputExpr, var, maxUses, path);
+
+ if (uses > 0)
{
- referencingExpr = inputExpr;
- break;
+ if (uses + numRefs > 1 || unsafe || !isSafeVar)
+ return false;
+
+ numRefs = 1;
}
}
@@ -794,47 +742,51 @@
}
case flwor_clause::window_clause:
{
- if (!declared)
- continue;
-
- assert(varQuant == TypeConstants::QUANT_ONE);
-
const window_clause* wc = static_cast<const window_clause*>(clause);
expr* domExpr = wc->get_expr();
flwor_wincond* startCond = wc->get_win_start();
flwor_wincond* stopCond = wc->get_win_stop();
- expr* startExpr = (startCond == NULL ? NULL : startCond->get_cond());
- expr* stopExpr = (stopCond == NULL ? NULL : stopCond->get_cond());
-
- if (domExpr->is_sequential())
- return false;
-
- if (std::find(refpath.begin(), refpath.end(), domExpr) != refpath.end())
- {
- referencingExpr = domExpr;
- break;
- }
-
- if (domExpr->get_return_type()->max_card() > 1)
- return false;
-
- if (std::find(refpath.begin(), refpath.end(), startExpr) != refpath.end())
- {
- referencingExpr = domExpr;
- break;
- }
-
- if (std::find(refpath.begin(), refpath.end(), stopExpr) != refpath.end())
- {
- referencingExpr = domExpr;
- break;
+
+ int uses = expr_tools::count_variable_uses(domExpr, var, maxUses, path);
+
+ if (uses > 0)
+ {
+ if (uses + numRefs > 1 || unsafe || !isSafeVar || domExpr->is_sequential())
+ return false;
+
+ numRefs = 1;
+ }
+ else if (numRefs == 0)
+ {
+ if (domExpr->is_sequential())
+ unsafe = true;
+
+ if (domExpr->get_return_type()->max_card() >= 2)
+ unsafe = true;
+ }
+
+ if (startCond != NULL)
+ {
+ int uses = expr_tools::count_variable_uses(startCond->get_cond(), var, 1, NULL);
+
+ if (uses > 0)
+ return false;
+ }
+
+ if (stopCond != NULL)
+ {
+ int uses = expr_tools::count_variable_uses(stopCond->get_cond(), var, 1, NULL);
+
+ if (uses > 0)
+ return false;
}
break;
}
case flwor_clause::materialize_clause:
{
- return false;
+ unsafe = true;
+ break;
}
case flwor_clause::count_clause:
{
@@ -847,46 +799,54 @@
}
}
- if (referencingExpr == NULL)
- {
- expr* retExpr = flwor.get_return_expr();
-
- if (retExpr->is_sequential())
- return false;
-
- if (std::find(refpath.begin(), refpath.end(), retExpr) != refpath.end())
- {
- if (varQuant != TypeConstants::QUANT_ONE)
- {
- // We are considering folding a FOR var whose domain expr may be the
- // empty sequence. We can fold only if doing so will cause the result
- // of the flwor expr to be the empty sequence in the case where the
- // domain expr will indeed be equal to the empty sequence.
- xqtref_t type = retExpr->get_return_type_with_empty_input(var);
-
- if (TypeOps::is_equal(tm, *type, *GENV_TYPESYSTEM.EMPTY_TYPE, retExpr->get_loc()))
- {
- referencingExpr = retExpr;
- }
- else
- {
- return false;
- }
- }
- else
- {
- referencingExpr = retExpr;
- }
- }
- }
-
- assert(referencingExpr != NULL);
-
- if (referencingExpr == NULL)
- return false;
-
- bool found = false;
- return !var_in_try_or_loop(var, referencingExpr, false, false, found);
+ expr* retExpr = theFlwor->get_return_expr();
+
+ std::vector<const expr*>* path = (numRefs > 0 ? NULL : &theRefPath);
+ int maxUses = 2 - numRefs;
+
+ int uses = expr_tools::count_variable_uses(retExpr, var, maxUses, path);
+
+ if (uses > 0)
+ {
+ if (uses + numRefs > 1 || unsafe || retExpr->is_sequential())
+ return false;
+
+ numRefs = 1;
+
+ if (varClause->get_kind() == flwor_clause::for_clause &&
+ varDomExpr->get_return_type()->get_quantifier() != TypeConstants::QUANT_ONE)
+ {
+ // We are considering folding a FOR var whose domain expr may be the
+ // empty sequence. We can fold only if doing so will cause the result
+ // of the flwor expr to be the empty sequence in the case where the
+ // domain expr will indeed be equal to the empty sequence.
+ xqtref_t type = retExpr->get_return_type_with_empty_input(var);
+
+ if (!TypeOps::is_equal(tm, *type, *GENV_TYPESYSTEM.EMPTY_TYPE, retExpr->get_loc()))
+ {
+ return false;
+ }
+ }
+ }
+ else if (numRefs == 0)
+ {
+ if (varDomExpr->isNonDiscardable() || !isSafeVar)
+ {
+ return false;
+ }
+ else
+ {
+#if 0
+ rCtx.getCompilerCB()->theXQueryDiagnostics->add_warning(
+ NEW_XQUERY_WARNING(zwarn::ZWST0001_UNUSED_VARIABLE,
+ WARN_PARAMS(var->get_name()->getStringValue()),
+ WARN_LOC(var->get_loc())));
+#endif
+ return true;
+ }
+ }
+
+ return !var_in_try_or_loop(theRefPath);
}
@@ -896,324 +856,195 @@
(a) for-loop within E, or
(b) try expr within E, or
(c) while expr within E
-
- The method traverses recursively the subtree of E looking for variable V and
- checking whether it crosses a loop or try expr. If it finds V and there is a
- loop or try expr in the path from E to V, it returns true; otherwise it returns
- false.
-
- Note: On the 1st (non-recursive) call, we know that E references V exactly
- once. But during a recursive call on a subexpr, the subexpr may or may not
- reference V.
********************************************************************************/
-static bool var_in_try_or_loop(
- const var_expr* v,
- const expr* e,
- bool inTryOrLoop,
- bool hasNodeConstr,
- bool& found)
+bool EliminateUnusedLetVars::var_in_try_or_loop(const std::vector<const expr*>& path)
{
- if (found)
- return false;
-
- expr_kind_t kind = e->get_expr_kind();
-
- if (kind == trycatch_expr_kind)
- {
- const trycatch_expr* tce = static_cast<const trycatch_expr *>(e);
-
- if (var_in_try_or_loop(v, tce->get_try_expr(), true, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- ZORBA_ASSERT(!found);
-
- csize numClauses = tce->clause_count();
-
- for (csize i = 0; i < numClauses; ++i)
- {
- if (var_in_try_or_loop(v,
- tce->get_catch_expr(i),
- inTryOrLoop,
- hasNodeConstr,
- found))
- {
- assert(found);
- return true;
- }
- }
-
- return false;
- }
- else if (kind == while_expr_kind)
- {
- const while_expr* we = static_cast<const while_expr *>(e);
-
- if (var_in_try_or_loop(v, we->get_body(), true, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- ZORBA_ASSERT(!found);
-
- return false;
- }
- else if (kind == flwor_expr_kind || kind == gflwor_expr_kind)
- {
- const flwor_expr& flwor = *static_cast<const flwor_expr *>(e);
-
- for (csize i = 0; i < flwor.num_clauses(); ++i)
- {
- const flwor_clause* c = flwor.get_clause(i);
-
- switch (c->get_kind())
- {
- case flwor_clause::for_clause:
- case flwor_clause::let_clause:
- {
- const forletwin_clause* flc = static_cast<const forletwin_clause*>(c);
- expr* domExpr = flc->get_expr();
-
- if (var_in_try_or_loop(v, domExpr, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
-
- if (c->get_kind() == flwor_clause::for_clause &&
- domExpr->get_return_type()->max_card() >= 2)
- {
- inTryOrLoop = true;
- }
-
- // test rbkt/zorba/extern/5890.xq illustrates why this check is needed
- //if (hasNodeConstr && domExpr->contains_node_construction())
- //{
- // return true;
- //}
-
- break;
- }
- case flwor_clause::window_clause:
- {
- const window_clause* wc = static_cast<const window_clause*>(c);
- expr* domExpr = wc->get_expr();
-
- if (var_in_try_or_loop(v, domExpr, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
-
- inTryOrLoop = true;
-
- flwor_wincond* startCond = wc->get_win_start();
- flwor_wincond* stopCond = wc->get_win_stop();
- expr* startExpr = startCond == NULL ? NULL : startCond->get_cond();
- expr* stopExpr = stopCond == NULL ? NULL : stopCond->get_cond();
-
- if (startExpr &&
- var_in_try_or_loop(v, startExpr, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
-
- if (stopExpr &&
- var_in_try_or_loop(v, stopExpr, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
-
- break;
- }
- case flwor_clause::group_clause:
- {
- const group_clause* gc = static_cast<const group_clause*>(c);
-
- flwor_clause::rebind_list_t::const_iterator ite = gc->beginGroupVars();
- flwor_clause::rebind_list_t::const_iterator end = gc->endGroupVars();
-
- for (; ite != end; ++ite)
- {
- expr* gExpr = (*ite).first;
-
- if (var_in_try_or_loop(v, gExpr, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
- }
-
- ite = gc->beginNonGroupVars();
- end = gc->endNonGroupVars();
-
- for (; ite != end; ++ite)
- {
- expr* ngExpr = (*ite).first;
-
- if (var_in_try_or_loop(v, ngExpr, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
- }
-
- break; // TODO
- }
- case flwor_clause::where_clause:
- {
- const where_clause* wc = static_cast<const where_clause*>(c);
-
- if (var_in_try_or_loop(v, wc->get_expr(), inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
-
- break;
- }
- case flwor_clause::order_clause:
- {
- const orderby_clause* oc = static_cast<const orderby_clause*>(c);
-
- std::vector<expr*>::const_iterator ite = oc->begin();
- std::vector<expr*>::const_iterator end = oc->end();
-
- for (; ite != end; ++ite)
- {
- if (var_in_try_or_loop(v, *ite, inTryOrLoop, hasNodeConstr, found))
- {
- assert(found);
- return true;
- }
-
- if (found)
- return false;
- }
-
- break;
- }
- case flwor_clause::count_clause:
- {
- break;
- }
- case flwor_clause::materialize_clause:
- {
- ZORBA_ASSERT(false);
- }
- default:
- {
- ZORBA_ASSERT(false);
- }
- }
- }
-
- return var_in_try_or_loop(v,
- flwor.get_return_expr(),
- inTryOrLoop,
- hasNodeConstr,
- found);
- }
- else if (e == v)
- {
- found = true;
- return inTryOrLoop;
- }
- else if (kind == if_expr_kind)
- {
- const if_expr* ifExpr = static_cast<const if_expr*>(e);
- const expr* condExpr = ifExpr->get_cond_expr();
-
- if (var_in_try_or_loop(v, condExpr, inTryOrLoop, hasNodeConstr, found))
- return true;
-
- if (found)
- return false;
-
- // The var may actually be referenced in both the then and the else branches.
- // So, if we find it in the then branch and is not in try-or-loop in there,
- // we must still check the else branch.
-
- bool thenFound = false;
- bool elseFound = false;
- const expr* thenExpr = ifExpr->get_then_expr();
- const expr* elseExpr = ifExpr->get_else_expr();
-
- if (var_in_try_or_loop(v, thenExpr, inTryOrLoop, hasNodeConstr, thenFound))
- {
- assert(thenFound);
- found = true;
- return true;
- }
-
- if (var_in_try_or_loop(v, elseExpr, inTryOrLoop, hasNodeConstr, elseFound))
- {
- assert(elseFound);
- found = true;
- return true;
- }
-
- found = (thenFound || elseFound);
- return false;
- }
-#if 0
- else if (kind == elem_expr_kind ||
- kind == attr_expr_kind ||
- kind == pi_expr_kind ||
- kind == text_expr_kind ||
- kind == doc_expr_kind)
- {
- // test rbkt/zorba/extern/5890.xq illustrates why this check is needed
- if (hasNodeConstr)
- return true;
- }
-#endif
-
- // Or else navigate down all children
- ExprConstIterator ei(e);
- while (!ei.done())
- {
- if (var_in_try_or_loop(v, ei.get_expr(), inTryOrLoop, hasNodeConstr, found))
- {
- return true;
- }
-
- if (found)
- return false;
-
- ei.next();
- }
-
+ csize numSteps = path.size();
+
+ for (csize n = 0; n < numSteps; ++n)
+ {
+ const expr* node = path[n];
+
+ switch (node->get_expr_kind())
+ {
+ case trycatch_expr_kind:
+ case while_expr_kind:
+ {
+ return true;
+ }
+ case flwor_expr_kind:
+ case gflwor_expr_kind:
+ {
+ const expr* nextNode = path[n+1];
+
+ const flwor_expr* flwor = static_cast<const flwor_expr*>(node);
+
+ bool foundRefClause = false;
+ csize numClauses = flwor->num_clauses();
+
+ for (csize i = 0; i < numClauses && ! foundRefClause; ++i)
+ {
+ flwor_clause* c = flwor->get_clause(i);
+ flwor_clause::ClauseKind ckind = c->get_kind();
+
+ switch (ckind)
+ {
+ case flwor_clause::for_clause:
+ case flwor_clause::let_clause:
+ case flwor_clause::window_clause:
+ {
+ forletwin_clause* flwc = static_cast<forletwin_clause*>(c);
+ expr* domExpr = flwc->get_expr();
+
+ if (nextNode == domExpr)
+ {
+ foundRefClause = true;
+ break;
+ }
+
+ if (ckind == flwor_clause::window_clause ||
+ (ckind == flwor_clause::for_clause &&
+ domExpr->get_return_type()->max_card() >= 2))
+ {
+ return true;
+ }
+
+ break;
+ }
+ case flwor_clause::group_clause:
+ {
+ group_clause* gc = static_cast<group_clause*>(c);
+
+ flwor_clause::rebind_list_t::const_iterator ite = gc->beginGroupVars();
+ flwor_clause::rebind_list_t::const_iterator end = gc->endGroupVars();
+
+ for (; ite != end; ++ite)
+ {
+ expr* gExpr = (*ite).first;
+
+ if (nextNode == gExpr)
+ {
+ foundRefClause = true;
+ break;
+ }
+ }
+
+ if (foundRefClause)
+ break;
+
+ ite = gc->beginNonGroupVars();
+ end = gc->endNonGroupVars();
+
+ for (; ite != end; ++ite)
+ {
+ expr* ngExpr = (*ite).first;
+
+ if (nextNode == ngExpr)
+ {
+ foundRefClause = true;
+ break;
+ }
+ }
+
+ break;
+ }
+ case flwor_clause::where_clause:
+ {
+ where_clause* wc = static_cast<where_clause*>(c);
+
+ if (nextNode == wc->get_expr())
+ foundRefClause = true;
+
+ break;
+ }
+ case flwor_clause::order_clause:
+ {
+ orderby_clause* oc = static_cast<orderby_clause*>(c);
+
+ std::vector<expr*>::const_iterator ite = oc->begin();
+ std::vector<expr*>::const_iterator end = oc->end();
+
+ for (; ite != end; ++ite)
+ {
+ if (nextNode == *ite)
+ {
+ foundRefClause = true;
+ break;
+ }
+ }
+
+ break;
+ }
+ case flwor_clause::count_clause:
+ {
+ break;
+ }
+ case flwor_clause::materialize_clause:
+ {
+ ZORBA_ASSERT(false);
+ }
+ default:
+ {
+ ZORBA_ASSERT(false);
+ }
+ }
+ } // for each clause
+
+ if (!foundRefClause)
+ {
+ ZORBA_ASSERT(nextNode == flwor->get_return_expr());
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+ } // for each path step
+
return false;
}
+/******************************************************************************
+
+******************************************************************************/
+static bool is_trivial_expr(const expr* e)
+{
+ switch (e->get_expr_kind())
+ {
+ case const_expr_kind:
+ {
+ return true;
+ }
+ case var_expr_kind:
+ {
+ const var_expr* ve = static_cast<const var_expr*>(e);
+ enum var_expr::var_kind k = ve->get_kind();
+
+ // NOTE: An arg var is not materialized, and as a result, it cannot be
+ // referenced more than once or be refeneced inside a loop or try block.
+ // Therefore, an arg var that appears as the domain expr of a LET var
+ // cannot trivially substitute the LET var.
+ if (k == var_expr::arg_var ||
+ k == var_expr::local_var ||
+ (k == var_expr::prolog_var && ve->is_mutable()))
+ return false;
+
+ assert(!e->isNonDiscardable());
+ return true;
+ }
+ case wrapper_expr_kind:
+ {
+ return is_trivial_expr(static_cast<const wrapper_expr*>(e)->get_input());
+ }
+ default:
+ return false;
+ }
+}
+
+
+
////////////////////////////////////////////////////////////////////////////////
// //
// RefactorPredFLWOR //
@@ -1410,7 +1241,7 @@
assert(udf == rCtx.theUDF);
- for_clause* forClause = posVar->get_for_clause();
+ for_clause* forClause = posVar->get_forlet_clause();
expr* domainExpr = forClause->get_expr();
fo_expr* result;
@@ -1658,7 +1489,7 @@
}
}
- for_clause* forClause = posVar->get_for_clause();
+ for_clause* forClause = posVar->get_forlet_clause();
if (forClause->is_allowing_empty())
return false;
=== modified file 'src/compiler/rewriter/rules/fold_rules.cpp'
--- src/compiler/rewriter/rules/fold_rules.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/fold_rules.cpp 2012-10-26 18:28:41 +0000
@@ -51,11 +51,9 @@
namespace zorba {
-static bool standalone_expr(expr*);
-
-static bool already_folded(expr*, RewriterContext&);
-
-static expr* partial_eval_fo (RewriterContext&, fo_expr*);
+static bool execute(CompilerCB*, expr* node, store::Item_t& result);
+
+static expr* partial_eval_fo(RewriterContext&, fo_expr*);
static expr* partial_eval_logic(fo_expr*, bool, RewriterContext&);
@@ -67,86 +65,6 @@
/*******************************************************************************
-
-********************************************************************************/
-static expr* execute(
- CompilerCB* compilercb,
- expr* node,
- std::vector<store::Item_t>& result)
-{
- ulong nextVarId = 1;
- PlanIter_t plan = codegen("const-folded expr", node, compilercb, nextVarId);
-
- QueryLoc loc = LOC (node);
- store::Item_t item;
-
- CompilerCB expr_ccb(*compilercb);
- expr_ccb.theRootSctx = node->get_sctx();
-
- try
- {
- //std::cout << "Const folding expr : " << std::endl;
- //node->put(std::cout);
- //std::cout << std::endl;
-
- PlanWrapperHolder pw(new PlanWrapper(plan,
- &expr_ccb,
- 0, // dynamic ctx
- NULL, // xquery
- 0, // stack depth
- expr_ccb.theHaveTimeout,
- expr_ccb.theTimeout));
- for (;;)
- {
- if (!pw->next(item))
- {
- break;
- }
-
- if (item->isError())
- {
- node->setUnfoldable(ANNOTATION_TRUE_FIXED);
- node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
- return node;
- }
-
- result.push_back(item);
- }
-
- return NULL;
- }
- catch (ZorbaException const&)
- {
- node->setUnfoldable(ANNOTATION_TRUE_FIXED);
- node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
- return node;
- // TODO:
- // we had to disable folding of errors because the FnErrorIterator
- // was erroneously used. It always raises a ZorbaUserError (which is not correct).
-#if 0
- Error lErrorCode = e.theErrorCode;
- QueryLoc loc;
- loc.setLineBegin(e.theQueryLine);
- loc.setColumnBegin(e.theQueryColumn);
- store::Item_t qname;
- ITEM_FACTORY->createQName(qname,
- "http://www.w3.org/2005/xqt-errors",
- "err",
- error::ZorbaError::toString(lErrorCode).c_str());
- expr* err_expr = rCtx.theEM->create_fo_expr(node->get_sctx_id(),
- loc,
- BUILTIN_FUNC(FN_ERROR_2),
- rCtx.theEM->create_const_expr(node->get_sctx_id(), loc, qname),
- rCtx.theEM->create_const_expr(node->get_sctx_id(), loc, e.theDescription));
- err_expr->setUnfoldable(ANNOTATION_TRUE_FIXED);
- err_expr->setNonDiscardable(ANNOTATION_TRUE_FIXED);
- return err_expr;
-#endif
- }
-}
-
-
-/*******************************************************************************
Compute the NON_DISCARDABLE and UNFOLDABLE properties of expressions
The meaning/purpose of the NON_DISCARDABLE property is as follows:
@@ -457,64 +375,158 @@
fn:concatenate expr, if no item is returned by the evaluation of the const
expr.
********************************************************************************/
-
-RULE_REWRITE_PRE(FoldConst)
-{
- xqtref_t rtype = node->get_return_type();
-
- if (standalone_expr(node) &&
- ! already_folded(node, rCtx) &&
- node->getFreeVars().empty() &&
- ! node->isUnfoldable() &&
- rtype->max_card() <= 1)
- {
- std::vector<store::Item_t> result;
- expr* folded = execute(rCtx.getCompilerCB(), node, result);
- if (folded == NULL)
- {
- ZORBA_ASSERT (result.size () <= 1);
-
- if (result.size () == 1)
- {
- folded = rCtx.theEM->
- create_const_expr(node->get_sctx(), node->get_udf(), LOC(node), result[0]);
- }
- else
- {
- folded = rCtx.theEM->
- create_seq(node->get_sctx(), node->get_udf(), LOC(node));
- }
- }
- return folded;
- }
- return NULL;
-}
-
-
-RULE_REWRITE_POST(FoldConst)
-{
- return NULL;
-}
-
-
-static bool standalone_expr(expr* e)
-{
- expr_kind_t k = e->get_expr_kind();
- return k != match_expr_kind && k != axis_step_expr_kind;
-}
-
-
-static bool already_folded(expr* e, RewriterContext& rCtx)
-{
- if (e->get_expr_kind () == const_expr_kind)
+expr* FoldConst::apply(RewriterContext& rCtx, expr* node, bool& modified)
+{
+ expr_kind_t k = node->get_expr_kind();
+ xqtref_t rtype = node->get_return_type(); // DO NOT MOVE THIS !!!!
+
+ switch (k)
+ {
+ case const_expr_kind:
+ case match_expr_kind:
+ case axis_step_expr_kind:
+ {
+ break;
+ }
+ case fo_expr_kind:
+ {
+ fo_expr* fo = static_cast<fo_expr*>(node);
+
+ if (fo->get_func()->getKind() == FunctionConsts::OP_CONCATENATE_N &&
+ fo->num_args() == 0)
+ break;
+ }
+
+ default:
+ {
+ if (node->getFreeVars().empty() &&
+ ! node->isUnfoldable() &&
+ rtype->max_card() <= 1)
+ {
+ store::Item_t result;
+ bool folded = execute(rCtx.getCompilerCB(), node, result);
+
+ if (folded)
+ {
+ expr* foldedExpr;
+
+ if (result)
+ {
+ foldedExpr = rCtx.theEM->
+ create_const_expr(node->get_sctx(), node->get_udf(), LOC(node), result);
+ }
+ else
+ {
+ foldedExpr = rCtx.theEM->
+ create_seq(node->get_sctx(), node->get_udf(), LOC(node));
+ }
+
+ modified = true;
+ return foldedExpr;
+ }
+ }
+
+ break;
+ }
+ }
+
+ ExprIterator iter(node);
+
+ while (!iter.done())
+ {
+ expr* new_e = apply(rCtx, **iter, modified);
+ if (new_e != NULL)
+ {
+ **iter = new_e;
+ }
+
+ iter.next();
+ }
+
+ return NULL;
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+static bool execute(
+ CompilerCB* compilercb,
+ expr* node,
+ store::Item_t& result)
+{
+ ulong nextVarId = 1;
+ PlanIter_t plan = codegen("const-folded expr", node, compilercb, nextVarId);
+
+ QueryLoc loc = LOC (node);
+ store::Item_t item;
+
+ CompilerCB expr_ccb(*compilercb);
+ expr_ccb.theRootSctx = node->get_sctx();
+
+ try
+ {
+ //std::cout << "Const folding expr : " << std::endl;
+ //node->put(std::cout);
+ //std::cout << std::endl;
+
+ PlanWrapperHolder pw(new PlanWrapper(plan,
+ &expr_ccb,
+ 0, // dynamic ctx
+ NULL, // xquery
+ 0, // stack depth
+ expr_ccb.theHaveTimeout,
+ expr_ccb.theTimeout));
+ if (pw->next(item))
+ {
+ if (item->isError())
+ {
+ node->setUnfoldable(ANNOTATION_TRUE_FIXED);
+ node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
+ return false;
+ }
+
+ result.transfer(item);
+
+ ZORBA_ASSERT(!pw->next(item));
+ }
+ else
+ {
+ result = NULL;
+ }
+
return true;
- if (e->get_expr_kind () != fo_expr_kind)
+ }
+ catch (ZorbaException const&)
+ {
+ node->setUnfoldable(ANNOTATION_TRUE_FIXED);
+ node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
return false;
- const fo_expr* fo = dynamic_cast<fo_expr*>(e);
-
- return (fo->get_func()->getKind() == FunctionConsts::OP_CONCATENATE_N &&
- fo->num_args() == 0);
+ // TODO:
+ // we had to disable folding of errors because the FnErrorIterator
+ // was erroneously used. It always raises a ZorbaUserError (which is not correct).
+#if 0
+ Error lErrorCode = e.theErrorCode;
+ QueryLoc loc;
+ loc.setLineBegin(e.theQueryLine);
+ loc.setColumnBegin(e.theQueryColumn);
+ store::Item_t qname;
+ ITEM_FACTORY->createQName(qname,
+ "http://www.w3.org/2005/xqt-errors",
+ "err",
+ error::ZorbaError::toString(lErrorCode).c_str());
+ expr* err_expr = rCtx.theEM->
+ create_fo_expr(node->get_sctx_id(),
+ loc,
+ BUILTIN_FUNC(FN_ERROR_2),
+ rCtx.theEM->create_const_expr(node->get_sctx(), loc, qname),
+ rCtx.theEM->create_const_expr(node->get_sctx(), loc, e.theDescription));
+ err_expr->setUnfoldable(ANNOTATION_TRUE_FIXED);
+ err_expr->setNonDiscardable(ANNOTATION_TRUE_FIXED);
+ return err_expr;
+#endif
+ }
}
=== modified file 'src/compiler/rewriter/rules/hoist_rules.cpp'
--- src/compiler/rewriter/rules/hoist_rules.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/hoist_rules.cpp 2012-10-26 18:28:41 +0000
@@ -485,7 +485,7 @@
create_fo_expr(sctx, udf, loc, BUILTIN_FUNC(OP_HOIST_1), e);
hoisted->setFlags(e->getFlags());
- letvar->setFlags(e->getFlags());
+ //letvar->setFlags(e->getFlags());
let_clause* flref(rCtx.theEM->create_let_clause(sctx, loc, letvar, hoisted));
=== modified file 'src/compiler/rewriter/rules/index_join_rule.cpp'
--- src/compiler/rewriter/rules/index_join_rule.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/index_join_rule.cpp 2012-10-26 18:28:41 +0000
@@ -286,7 +286,7 @@
return false;
// The expr that defines the inner var must not depend on the outer var.
- expr* innerDomainExpr = predInfo.theInnerVar->get_for_clause()->get_expr();
+ expr* innerDomainExpr = predInfo.theInnerVar->get_forlet_clause()->get_expr();
if (checkVarDependency(rCtx, innerDomainExpr, outerVarId))
return false;
@@ -457,7 +457,7 @@
const QueryLoc& loc = predInfo.thePredicate->get_loc();
static_context* sctx = predInfo.thePredicate->get_sctx();
user_function* udf = predInfo.thePredicate->get_udf();
- for_clause* fc = predInfo.theInnerVar->get_for_clause();
+ for_clause* fc = predInfo.theInnerVar->get_forlet_clause();
assert(udf == rCtx.theUDF);
=== modified file 'src/compiler/rewriter/rules/ruleset.h'
--- src/compiler/rewriter/rules/ruleset.h 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/rules/ruleset.h 2012-10-26 18:28:41 +0000
@@ -41,14 +41,10 @@
PREPOST_RULE(EliminateTypeEnforcingOperations);
-PREPOST_RULE(EliminateUnusedLetVars);
-
PREPOST_RULE(RefactorPredFLWOR);
PREPOST_RULE(MergeFLWOR);
- //PREPOST_RULE(MarkFreeVars);
-
PREPOST_RULE(EliminateExtraneousPathSteps);
PREPOST_RULE(InlineFunctions);
@@ -59,23 +55,45 @@
/*******************************************************************************
********************************************************************************/
-class FoldConst : public PrePostRewriteRule
+class EliminateUnusedLetVars : public PrePostRewriteRule
{
protected:
- bool theFoldExpensiveOps;
+ flwor_expr * theFlwor;
+ std::vector<const expr*> theRefPath;
public:
- FoldConst(bool fold_expensive_ops)
+ EliminateUnusedLetVars()
:
- PrePostRewriteRule(RewriteRule::FoldConst, "FoldConst"),
- theFoldExpensiveOps(fold_expensive_ops)
+ PrePostRewriteRule(RewriteRule::EliminateUnusedLetVars, "EliminateUnusedLetVars"),
+ theFlwor(NULL)
{
+ theRefPath.reserve(32);
}
protected:
expr* rewritePre(expr* node, RewriterContext& rCtx);
expr* rewritePost(expr* node, RewriterContext& rCtx);
+
+ bool safe_to_fold_var(csize varClausePos, int& numRefs);
+
+ bool var_in_try_or_loop(const std::vector<const expr*>& path);
+};
+
+
+/*******************************************************************************
+
+********************************************************************************/
+class FoldConst : public RewriteRule
+{
+public:
+ FoldConst()
+ :
+ RewriteRule(RewriteRule::FoldConst, "FoldConst")
+ {
+ }
+
+ expr* apply(RewriterContext& rCtx, expr* node, bool& modified);
};
=== modified file 'src/compiler/rewriter/tools/expr_tools.cpp'
--- src/compiler/rewriter/tools/expr_tools.cpp 2012-10-24 11:32:56 +0000
+++ src/compiler/rewriter/tools/expr_tools.cpp 2012-10-26 18:28:41 +0000
@@ -81,7 +81,7 @@
return false;
}
- int thenCount = 0;
+ int thenCount = count;
std::vector<const expr*>* thenPath = (count == 0 ? path : NULL);
if (!count_var_uses_rec(ifExpr->get_then_expr(), var, limit, thenPath, thenCount))
@@ -91,7 +91,7 @@
return false;
}
- int elseCount = 0;
+ int elseCount = count;
std::vector<const expr*>* elsePath = (count == 0 ? path : NULL);
if (!count_var_uses_rec(ifExpr->get_else_expr(), var, limit, elsePath, elseCount))
@@ -101,7 +101,7 @@
return false;
}
- count += (thenCount > elseCount ? thenCount : elseCount);
+ count = (thenCount > elseCount ? thenCount : elseCount);
}
else
{
=== modified file 'src/compiler/translator/translator.cpp'
--- src/compiler/translator/translator.cpp 2012-10-24 12:49:43 +0000
+++ src/compiler/translator/translator.cpp 2012-10-26 18:28:41 +0000
@@ -1619,12 +1619,11 @@
Create a LET clause for the given LET variable "lv", with the given expr "e" as
its defining expression.
********************************************************************************/
-let_clause* wrap_in_letclause(expr* e, var_expr* lv)
+forlet_clause* wrap_in_letclause(expr* e, var_expr* lv)
{
assert (lv->get_kind () == var_expr::let_var);
- return theExprManager->
- create_let_clause(theRootSctx, e->get_loc(), lv, e);
+ return theExprManager->create_let_clause(theRootSctx, e->get_loc(), lv, e);
}
@@ -1633,7 +1632,7 @@
local sctx obj. Then, create a LET clause for this new var_expr, with the given
expr "e" as its defining expression.
********************************************************************************/
-let_clause* wrap_in_letclause(
+forlet_clause* wrap_in_letclause(
expr* e,
const QueryLoc& loc,
const QName* qname)
@@ -1647,7 +1646,7 @@
this new var_expr, with the given expr "e" as its defining expression. NOTE:
the internal var is not registered in the sctx.
********************************************************************************/
-let_clause* wrap_in_letclause(expr* e)
+forlet_clause* wrap_in_letclause(expr* e)
{
return wrap_in_letclause(e, create_temp_var(e->get_loc(), var_expr::let_var));
}
@@ -1657,7 +1656,7 @@
Create a FOR clause for the given FOR variable "fv" and its associated POS var
"pv" (pv may be NULL). Use the given expr "e" as the defining expr for "fv".
********************************************************************************/
-for_clause* wrap_in_forclause(expr* e, var_expr* fv, var_expr* pv)
+forlet_clause* wrap_in_forclause(expr* e, var_expr* fv, var_expr* pv)
{
assert(fv->get_kind () == var_expr::for_var);
if (pv != NULL)
@@ -1665,8 +1664,7 @@
assert(pv->get_kind() == var_expr::pos_var);
}
- return theExprManager->
- create_for_clause(theRootSctx, e->get_loc(), fv, e, pv);
+ return theExprManager->create_for_clause(theRootSctx, e->get_loc(), fv, e, pv);
}
@@ -1676,7 +1674,7 @@
Then, create a FOR clause for these new var_exprs, with the given expr as the
defining expression of the FOR var.
********************************************************************************/
-for_clause* wrap_in_forclause(
+forlet_clause* wrap_in_forclause(
expr* expr,
const QueryLoc& loc,
const QName* fv_qname,
@@ -1693,7 +1691,7 @@
this new var_expr, with the given expr as its defining expression. NOTE:
the internal var is not registered in the sctx.
********************************************************************************/
-for_clause* wrap_in_forclause(expr* expr, bool add_posvar)
+forlet_clause* wrap_in_forclause(expr* expr, bool add_posvar)
{
var_expr* fv = create_temp_var(expr->get_loc(), var_expr::for_var);
@@ -1769,13 +1767,13 @@
normalize_fo(countExpr);
- let_clause* lcLast = wrap_in_letclause(countExpr, loc, LAST_IDX_VARNAME);
+ forlet_clause* lcLast = wrap_in_letclause(countExpr, loc, LAST_IDX_VARNAME);
// Iterate over the input seq
for_clause* fcDot = wrap_in_forclause(lcInputSeq->get_var(),
- loc,
- DOT_VARNAME,
- DOT_POS_VARNAME);
+ loc,
+ DOT_VARNAME,
+ DOT_POS_VARNAME);
flworExpr->add_clause(lcInputSeq);
flworExpr->add_clause(lcLast);
flworExpr->add_clause(fcDot);
@@ -1784,9 +1782,9 @@
{
// Iterate over the input seq
for_clause* fcDot = wrap_in_forclause(inputExpr,
- loc,
- DOT_VARNAME,
- DOT_POS_VARNAME);
+ loc,
+ DOT_VARNAME,
+ DOT_POS_VARNAME);
flworExpr->add_clause(fcDot);
}
=== modified file 'test/rbkt/Queries/zorba/nodes/path.xq'
--- test/rbkt/Queries/zorba/nodes/path.xq 2012-07-13 18:51:36 +0000
+++ test/rbkt/Queries/zorba/nodes/path.xq 2012-10-26 18:28:41 +0000
@@ -7,3 +7,11 @@
$f := $a//@ns:f
return
( path($doc), path($b), path($d), path($f) )
+
+(:
+let
+ $a := <a><b/><b><c/></b><ns:e/></a>,
+ $b := $a/b[c]
+return
+ ( path($b) )
+:)
Follow ups