1 /*
2  * Copyright 2006-2008 The FLWOR Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "stdafx.h"
17 
18 #include "diagnostics/xquery_diagnostics.h"
19 
20 #include "system/globalenv.h"
21 
22 #include "context/static_context.h"
23 
24 #include "compiler/rewriter/rules/ruleset.h"
25 #include "compiler/rewriter/tools/expr_tools.h"
26 #include "compiler/rewriter/framework/rewriter.h"
27 
28 #include "compiler/expression/flwor_expr.h"
29 #include "compiler/expression/expr_iter.h"
30 #include "compiler/expression/expr.h"
31 
32 #include "compiler/codegen/plan_visitor.h"
33 #include "compiler/api/compilercb.h"
34 #include "compiler/api/compiler_api.h"
35 
36 #include "types/root_typemanager.h"
37 #include "types/typeops.h"
38 #include "types/casting.h"
39 
40 #include "functions/udf.h"
41 #include "functions/func_errors_and_diagnostics.h"
42 #include "functions/library.h"
43 
44 #include "runtime/util/plan_wrapper_holder.h"
45 #include "runtime/base/plan_iterator.h"
46 
47 #include "store/api/store.h"
48 #include "store/api/item_factory.h"
49 
50 #include <iterator>
51 
52 using namespace std;
53 
54 namespace zorba {
55 
56 static void remove_wincond_vars(const flwor_wincond*, expr::FreeVars&);
57 
58 static bool standalone_expr(expr*);
59 
60 static bool already_folded(expr*, RewriterContext&);
61 
62 static expr* partial_eval_fo (RewriterContext&, fo_expr*);
63 
64 static expr* partial_eval_logic(fo_expr*, bool, RewriterContext&);
65 
66 static expr* partial_eval_eq(RewriterContext&, fo_expr&);
67 
68 static expr* partial_eval_return_clause(flwor_expr* flworExpr, bool& modified, RewriterContext& rCtx);
69 
70 static bool maybe_needs_implicit_timezone(const fo_expr* fo);
71 
72 
73 /*******************************************************************************
74 
75 ********************************************************************************/
execute(CompilerCB * compilercb,expr * node,vector<store::Item_t> & result)76 static expr* execute (
77     CompilerCB* compilercb,
78     expr* node,
79     vector<store::Item_t>& result)
80 {
81   ulong nextVarId = 1;
82   PlanIter_t plan = codegen ("const-folded expr", node, compilercb, nextVarId);
83   QueryLoc loc = LOC (node);
84   store::Item_t item;
85 
86   CompilerCB expr_ccb(*compilercb);
87   expr_ccb.theRootSctx = node->get_sctx();
88   try
89   {
90     //std::cout << "Const folding expr : " << std::endl;
91     //node->put(std::cout);
92     //std::cout << std::endl;
93 
94     PlanWrapperHolder pw(new PlanWrapper(plan,
95                                          &expr_ccb,
96                                          0,      // dynamic ctx
97                                          NULL,   // xquery
98                                          0,      // stack depth
99                                          expr_ccb.theHaveTimeout,
100                                          expr_ccb.theTimeout));
101     for (;;)
102     {
103       if (!pw->next(item))
104       {
105         break;
106       }
107 
108       if (item->isError())
109       {
110         node->setUnfoldable(ANNOTATION_TRUE_FIXED);
111         node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
112         return node;
113       }
114 
115       result.push_back(item);
116     }
117 
118     return NULL;
119   }
120   catch (ZorbaException const&)
121   {
122     node->setUnfoldable(ANNOTATION_TRUE_FIXED);
123     node->setNonDiscardable(ANNOTATION_TRUE_FIXED);
124     return node;
125     // TODO:
126     // we had to disable folding of errors because the FnErrorIterator
127     // was erroneously used. It always raises a ZorbaUserError (which is not correct).
128 #if 0
129     Error lErrorCode = e.theErrorCode;
130     QueryLoc loc;
131     loc.setLineBegin(e.theQueryLine);
132     loc.setColumnBegin(e.theQueryColumn);
133     store::Item_t qname;
134     ITEM_FACTORY->createQName(qname,
135                               "http://www.w3.org/2005/xqt-errors",
136                               "err",
137                               error::ZorbaError::toString(lErrorCode).c_str());
138     expr* err_expr = rCtx.theEM->create_fo_expr(node->get_sctx_id(),
139                                   loc,
140                                   GET_BUILTIN_FUNCTION(FN_ERROR_2),
141                                   rCtx.theEM->create_const_expr(node->get_sctx_id(), loc, qname),
142                                   rCtx.theEM->create_const_expr(node->get_sctx_id(), loc, e.theDescription));
143     err_expr->setUnfoldable(ANNOTATION_TRUE_FIXED);
144     err_expr->setNonDiscardable(ANNOTATION_TRUE_FIXED);
145     return err_expr;
146 #endif
147   }
148 }
149 
150 
151 /*******************************************************************************
152   Compute the NON_DISCARDABLE and UNFOLDABLE properties of expressions
153 
154   The meaning/purpose of the NON_DISCARDABLE property is as follows:
155   Some expressions can be computed (at leat partially) during compilation time
156   based on the static type of their argument. For example, count(E) can be
157   replaced by const 1 if the static type of E has quantifier 1. Also,
158   castable(E, target_type) can be replaced by const true if the static type of
159   E is a subtype of target_type. However, E may have "side-effects", which
160   prevent such a replacement. For example, it may be a treat expr, whose
161   semantics is to return an error during runtime if the arg of the treat expr
162   does not have the corect type. We flag such exprs as non-discardable so that
163   no (partial) evaluation of parent exprs is done.
164 
165   The NON_DISCARDABLE property is used during the application of the PartialEval
166   rule below.
167 ********************************************************************************/
apply(RewriterContext & rCtx,expr * node,bool & modified)168 expr* MarkExprs::apply(RewriterContext& rCtx, expr* node, bool& modified)
169 {
170   BoolAnnotationValue saveNonDiscardable = node->getNonDiscardable();
171   BoolAnnotationValue saveUnfoldable = node->getUnfoldable();
172   BoolAnnotationValue saveContainsRecursiveCall = node->getContainsRecursiveCall();
173 
174   // By default, an expr is discardable, foldable, and does not contain
175   // recursive calls
176   BoolAnnotationValue curNonDiscardable = ANNOTATION_FALSE;
177   BoolAnnotationValue curUnfoldable = ANNOTATION_FALSE;
178   BoolAnnotationValue curContainsRecursiveCall = ANNOTATION_FALSE;
179 
180   // Process udfs: If the current expr is a udf invocation, optimize the udf
181   // body, if not optimized already, and determine whether the invocation is
182   // a recursive call or not.
183   if (node->get_expr_kind() == fo_expr_kind)
184   {
185     fo_expr* fo = static_cast<fo_expr *>(node);
186     function* f = fo->get_func();
187 
188     if (f->isUdf())
189     {
190       user_function* udf = static_cast<user_function*>(f);
191 
192       if (!udf->isOptimized())
193       {
194         udf->optimize();
195       }
196 
197       if (rCtx.theUDF != NULL &&
198           rCtx.theUDF->isMutuallyRecursiveWith(udf))
199       {
200         curContainsRecursiveCall = ANNOTATION_TRUE;
201       }
202     }
203   }
204 
205   // Process the subexprs of the current expr. If any of the children is
206   // nondiscardable, unfoldable, or contains recursive calls, then the current
207   // expr is also nondiscardable, unfoldable, or contains recursive calls.
208   ExprConstIterator iter(node);
209   while(!iter.done())
210   {
211     expr* childExpr = iter.get_expr();
212 
213     apply(rCtx, childExpr, modified);
214 
215     if (childExpr->isNonDiscardable())
216       curNonDiscardable = ANNOTATION_TRUE;
217 
218     if (childExpr->isUnfoldable())
219       curUnfoldable = ANNOTATION_TRUE;
220 
221     if (childExpr->containsRecursiveCall())
222       curContainsRecursiveCall = ANNOTATION_TRUE;
223 
224     iter.next();
225   }
226 
227   // Certain exprs are nondiscardable independently from their children.
228   if (saveNonDiscardable != ANNOTATION_TRUE_FIXED)
229   {
230     if (node->is_sequential())
231     {
232       curNonDiscardable = ANNOTATION_TRUE_FIXED;
233     }
234     else
235     {
236       switch (node->get_expr_kind())
237       {
238       case fo_expr_kind:
239       {
240         fo_expr* fo = static_cast<fo_expr *>(node);
241         function* f = fo->get_func();
242 
243         bool isErrorFunc = (dynamic_cast<const fn_error*>(f) != NULL);
244 
245         if (f->getKind() == FunctionConsts::FN_TRACE_2 ||
246             isErrorFunc)
247         {
248           curNonDiscardable = ANNOTATION_TRUE_FIXED;
249         }
250 
251         break;
252       }
253 
254       case cast_expr_kind:
255       case treat_expr_kind:
256       case promote_expr_kind:
257       {
258         curNonDiscardable = ANNOTATION_TRUE_FIXED;
259         break;
260       }
261 
262       default:
263       {
264         break;
265       }
266       }
267     }
268   }
269 
270   // Certain exprs are unfoldable independently from their children
271   if (saveUnfoldable != ANNOTATION_TRUE_FIXED)
272   {
273     if (node->is_sequential())
274     {
275       curUnfoldable = ANNOTATION_TRUE_FIXED;
276     }
277     else
278     {
279       switch (node->get_expr_kind())
280       {
281       case fo_expr_kind:
282       {
283         fo_expr* fo = static_cast<fo_expr *>(node);
284         function* f = fo->get_func();
285 
286         bool isErrorFunc = (dynamic_cast<const fn_error*>(f) != NULL);
287 
288         // Do not fold functions that always require access to the dynamic context,
289         // or may need to access the implicit timezone (which is also in the dynamic
290         // constext).
291         if (isErrorFunc ||
292             f->accessesDynCtx() ||
293             maybe_needs_implicit_timezone(fo) ||
294             !f->isDeterministic())
295         {
296           curUnfoldable = ANNOTATION_TRUE_FIXED;
297         }
298 
299         break;
300       }
301 
302       case var_expr_kind:
303       {
304         var_expr::var_kind varKind = static_cast<var_expr *>(node)->get_kind();
305 
306         if (varKind == var_expr::prolog_var || varKind == var_expr::local_var)
307           curUnfoldable = ANNOTATION_TRUE_FIXED;
308 
309         break;
310       }
311 
312       // Node constructors are unfoldable because if a node constructor is inside
313       // a loop, then it will create a different xml tree every time it is invoked,
314       // even if the constructor itself is "constant" (i.e. does not reference any
315       // varialbes)
316       case elem_expr_kind:
317       case attr_expr_kind:
318       case text_expr_kind:
319       case pi_expr_kind:
320       case doc_expr_kind:
321       {
322         curUnfoldable = ANNOTATION_TRUE_FIXED;
323         break;
324       }
325 
326       case delete_expr_kind:
327       case insert_expr_kind:
328       case rename_expr_kind:
329       case replace_expr_kind:
330       {
331         curUnfoldable = ANNOTATION_TRUE_FIXED;
332         break;
333       }
334 
335       default:
336       {
337         break;
338       }
339       }
340     }
341   }
342 
343   if (saveNonDiscardable != curNonDiscardable &&
344       saveNonDiscardable != ANNOTATION_TRUE_FIXED)
345   {
346     node->setNonDiscardable(curNonDiscardable);
347     modified = true;
348   }
349 
350   if (saveUnfoldable != curUnfoldable &&
351       saveUnfoldable != ANNOTATION_TRUE_FIXED)
352   {
353     node->setUnfoldable(curUnfoldable);
354     modified = true;
355   }
356 
357   if (saveContainsRecursiveCall != curContainsRecursiveCall &&
358       saveContainsRecursiveCall != ANNOTATION_TRUE_FIXED)
359   {
360     node->setContainsRecursiveCall(curContainsRecursiveCall);
361     modified = true;
362   }
363 
364   return NULL;
365 }
366 
367 
maybe_needs_implicit_timezone(const fo_expr * fo)368 static bool maybe_needs_implicit_timezone(const fo_expr* fo)
369 {
370   TypeManager* tm = fo->get_type_manager();
371 
372   const function* f = fo->get_func();
373   FunctionConsts::FunctionKind fkind = f->getKind();
374   xqtref_t type0 = (fo->num_args() > 0 ? fo->get_arg(0)->get_return_type() : NULL);
375   xqtref_t type1 = (fo->num_args() > 1 ? fo->get_arg(1)->get_return_type() : NULL);
376 
377   return ( ((f->isComparisonFunction() ||
378              f->arithmeticKind() == ArithmeticConsts::SUBTRACTION) &&
379             (TypeOps::maybe_date_time(tm, *type0) ||
380              TypeOps::maybe_date_time(tm, *type1)))
381            ||
382            ((fkind == FunctionConsts::FN_DISTINCT_VALUES_1 ||
383              fkind == FunctionConsts::FN_DISTINCT_VALUES_2 ||
384              fkind == FunctionConsts::FN_MIN_1 ||
385              fkind == FunctionConsts::FN_MIN_2 ||
386              fkind == FunctionConsts::FN_MAX_1 ||
387              fkind == FunctionConsts::FN_MAX_2)
388             && TypeOps::maybe_date_time(tm, *TypeOps::prime_type(tm, *type0))) );
389 }
390 
391 
392 /*******************************************************************************
393   For each expr E, collect all the variables that are referenced directly by E
394   and its subexpressions.
395 ********************************************************************************/
396 
RULE_REWRITE_PRE(MarkFreeVars)397 RULE_REWRITE_PRE(MarkFreeVars)
398 {
399   return NULL;
400 }
401 
RULE_REWRITE_POST(MarkFreeVars)402 RULE_REWRITE_POST(MarkFreeVars)
403 {
404   expr::FreeVars& freevars = node->getFreeVars();
405 
406   freevars.clear();
407 
408   if (node->get_expr_kind() == var_expr_kind)
409   {
410     var_expr* v = static_cast<var_expr *>(node);
411     freevars.insert(v);
412   }
413   else
414   {
415     // Get the free vars of each child expr and add them to the free vars of the
416     // parent.
417     ExprIterator iter(node);
418     while (!iter.done())
419     {
420       expr* e = **iter;
421 
422       const expr::FreeVars& kfv = e->getFreeVars();
423       std::copy(kfv.begin(),
424                 kfv.end(),
425                 inserter(freevars, freevars.begin()));
426 
427       iter.next();
428     }
429 
430     // For a flwor expr, remove the vars defined by the flwor expr itself from
431     // the flwor free vars .
432     if (node->get_expr_kind() == flwor_expr_kind ||
433         node->get_expr_kind() == gflwor_expr_kind)
434     {
435       flwor_expr* flwor = dynamic_cast<flwor_expr *> (node);
436       for (flwor_expr::clause_list_t::const_iterator i = flwor->clause_begin();
437            i != flwor->clause_end();
438            ++i)
439       {
440         const flwor_clause* c = *i;
441 
442         if (c->get_kind() == flwor_clause::for_clause)
443         {
444           const for_clause* fc = static_cast<const for_clause *>(c);
445 
446           freevars.erase(fc->get_var());
447           if (fc->get_pos_var() != NULL)
448             freevars.erase(fc->get_pos_var());
449         }
450         else if (c->get_kind() == flwor_clause::let_clause)
451         {
452           const let_clause* lc = static_cast<const let_clause *>(c);
453 
454           freevars.erase(lc->get_var());
455         }
456         else if (c->get_kind() == flwor_clause::window_clause)
457         {
458           const window_clause* wc = static_cast<const window_clause *>(c);
459 
460           freevars.erase(wc->get_var());
461 
462           flwor_wincond* startCond = wc->get_win_start();
463           flwor_wincond* stopCond = wc->get_win_stop();
464 
465           if (startCond != NULL)
466             remove_wincond_vars(startCond, freevars);
467 
468           if (stopCond != NULL)
469             remove_wincond_vars(stopCond, freevars);
470         }
471         else if (c->get_kind() == flwor_clause::group_clause)
472         {
473           const group_clause* gc = static_cast<const group_clause *>(c);
474 
475           const flwor_clause::rebind_list_t& gvars = gc->get_grouping_vars();
476           csize numGroupVars = gvars.size();
477 
478           for (csize i = 0; i < numGroupVars; ++i)
479           {
480             freevars.erase(gvars[i].second);
481           }
482 
483           const flwor_clause::rebind_list_t& ngvars = gc->get_nongrouping_vars();
484           csize numNonGroupVars = ngvars.size();
485 
486           for (csize i = 0; i < numNonGroupVars; ++i)
487           {
488             freevars.erase(ngvars[i].second);
489           }
490         }
491         else if (c->get_kind() == flwor_clause::count_clause)
492         {
493           const count_clause* cc = static_cast<const count_clause *>(c);
494 
495           freevars.erase(cc->get_var());
496         }
497       }
498     }
499   }
500 
501   return NULL;
502 }
503 
504 
remove_wincond_vars(const flwor_wincond * cond,expr::FreeVars & freevars)505 static void remove_wincond_vars(
506     const flwor_wincond* cond,
507     expr::FreeVars& freevars)
508 {
509   const flwor_wincond::vars& inVars = cond->get_in_vars();
510   const flwor_wincond::vars& outVars = cond->get_out_vars();
511 
512   freevars.erase(inVars.posvar);
513   freevars.erase(inVars.curr);
514   freevars.erase(inVars.prev);
515   freevars.erase(inVars.next);
516 
517   freevars.erase(outVars.posvar);
518   freevars.erase(outVars.curr);
519   freevars.erase(outVars.prev);
520   freevars.erase(outVars.next);
521 }
522 
523 
524 /*******************************************************************************
525   Execute const exprs that return at most one item as a result. Replace such
526   exprs by either a const_expr whose value is the returned item, or an empty
527   fn:concatenate expr, if no item is returned by the evaluation of the const
528   expr.
529 ********************************************************************************/
530 
RULE_REWRITE_PRE(FoldConst)531 RULE_REWRITE_PRE(FoldConst)
532 {
533   xqtref_t rtype = node->get_return_type();
534 
535   if (standalone_expr(node) &&
536       ! already_folded(node, rCtx) &&
537       node->getFreeVars().empty() &&
538       ! node->isUnfoldable() &&
539       rtype->max_card() <= 1)
540   {
541     vector<store::Item_t> result;
542     expr* folded = execute(rCtx.getCompilerCB(), node, result);
543     if (folded == NULL)
544     {
545       ZORBA_ASSERT (result.size () <= 1);
546       folded = (result.size () == 1 ?
547                 ((expr*) (rCtx.theEM->create_const_expr(node->get_sctx(), LOC(node), result[0]))) :
548                 ((expr*) (rCtx.theEM->create_seq(node->get_sctx(), LOC(node)))));
549     }
550     return folded;
551   }
552   return NULL;
553 }
554 
RULE_REWRITE_POST(FoldConst)555 RULE_REWRITE_POST(FoldConst)
556 {
557   return NULL;
558 }
559 
560 
standalone_expr(expr * e)561 static bool standalone_expr(expr* e)
562 {
563   expr_kind_t k = e->get_expr_kind ();
564   return k != match_expr_kind && k != axis_step_expr_kind;
565 }
566 
567 
already_folded(expr * e,RewriterContext & rCtx)568 static bool already_folded(expr* e, RewriterContext& rCtx)
569 {
570   if (e->get_expr_kind () == const_expr_kind)
571     return true;
572   if (e->get_expr_kind () != fo_expr_kind)
573     return false;
574 
575   const fo_expr* fo = dynamic_cast<fo_expr*>(e);
576 
577   return (fo->get_func()->getKind() == FunctionConsts::OP_CONCATENATE_N &&
578           fo->num_args() == 0);
579 }
580 
581 
582 /*******************************************************************************
583 
584   The PartialEval rule performs the following kinds of rewrites:
585 
586   Replace "castable(E, targetType)" or "instance-of(E, targetType)" with true, if
587   the return type of E is a subtype of targetType and E is not NONDISCARDABLE_EXPR.
588 
589   Replace "instance-of(E, targetType)" with false if the intersection of return
590   type of E and the targetType is empty and E is not NONDISCARDABLE_EXPR.
591 
592   Replace "if (cond) then E1 else E2" with E1 or E2 if cond is a const expr whose
593   EBV is true or false respectively.
594 
595   Rewrite "and" or "or" exprs which have one or more operands that are constants.
596   Do this only if none of the operands is NONDISCARDABLE.
597   For example:
598   E and false --> false
599   E and true  --> E
600 
601   Rewrite exprs of the form "count(E) = const" or "count(E) eq const".
602   For example:
603   count(E) = -1 --> false, if E is not NONDISCARDABLE
604   count(E) = 0  --> fn:empty(E)
605   count(E) = 1  --> fn:exectly-one-noraise(E)
606   count(E) = 10 --> fn:exectly-one-noraise(fn:subsequence(E, 10, 2))
607 
608   If E is not NONDISCARDABLE_EXPR:
609   - Replace count(E) with 1 or 0 if the return type of E has QUANT_ONE or is the
610     emtpy sequence.
611   - Replace empty(E) with true if the return type of E is the emtpy sequence, or
612     false if the return type of E has QUANT_ONE or QUANT_PLUS.
613   - Replace exists(E) with false if the return type of E is the emtpy sequence, or
614     truee if the return type of E has QUANT_ONE or QUANT_PLUS.
615 
616   Replace EBV(E) with true if the return type of E is subtype on node()+ and E
617   is not NONDISCARDABLE.
618 
619 ********************************************************************************/
620 
RULE_REWRITE_PRE(PartialEval)621 RULE_REWRITE_PRE(PartialEval)
622 {
623   TypeManager* tm = node->get_type_manager();
624 
625   // if node is a castable or instance-of expr
626   const castable_base_expr* cbe = NULL;
627   if ((cbe = dynamic_cast<const castable_base_expr *>(node)) != NULL)
628   {
629     expr* arg = cbe->get_input();
630 
631     if (arg->isNonDiscardable())
632       return NULL;
633 
634     xqtref_t argType = arg->get_return_type();
635     xqtref_t targetType = cbe->get_target_type();
636 
637     if (TypeOps::is_subtype(tm, *argType, *targetType, node->get_loc()))
638     {
639       return rCtx.theEM->create_const_expr(node->get_sctx(), LOC(node), true);
640     }
641     else if (node->get_expr_kind() == instanceof_expr_kind)
642     {
643       instanceof_expr* ioExpr = static_cast<instanceof_expr*>(node);
644 
645       if (ioExpr->getCheckPrimeOnly())
646       {
647         argType = TypeOps::prime_type(tm, *argType);
648         targetType = TypeOps::prime_type(tm, *targetType);
649       }
650 
651       return (TypeOps::intersect_type(*argType, *targetType, tm) ==
652               GENV_TYPESYSTEM.NONE_TYPE ?
653               rCtx.theEM->create_const_expr(node->get_sctx(), LOC(node), false) :
654               NULL);
655     }
656     else
657     {
658       return NULL;
659     }
660   }
661 
662   switch (node->get_expr_kind())
663   {
664   case if_expr_kind:
665   {
666     if_expr* ite = dynamic_cast<if_expr *> (node);
667     const const_expr* cond = dynamic_cast<const const_expr*>(ite->get_cond_expr());
668     if (cond != NULL)
669     {
670       return (cond->get_val()->getBooleanValue() ?
671               ite->get_then_expr() :
672               ite->get_else_expr());
673     }
674     break;
675   }
676 
677   case fo_expr_kind:
678   {
679     return partial_eval_fo(rCtx, dynamic_cast<fo_expr *>(node));
680   }
681 
682   default:
683     break;
684   }
685 
686   return NULL;
687 }
688 
RULE_REWRITE_POST(PartialEval)689 RULE_REWRITE_POST(PartialEval)
690 {
691   return NULL;
692 }
693 
694 
partial_eval_fo(RewriterContext & rCtx,fo_expr * fo)695 static expr* partial_eval_fo(RewriterContext& rCtx, fo_expr* fo)
696 {
697   TypeManager* tm = fo->get_type_manager();
698 
699   const function* f = fo->get_func();
700   FunctionConsts::FunctionKind fkind = f->getKind();
701 
702   if (fkind == FunctionConsts::OP_OR_N && !fo->isNonDiscardable())
703   {
704     return partial_eval_logic(fo, true, rCtx);
705   }
706   else if (fkind == FunctionConsts::OP_AND_N && !fo->isNonDiscardable())
707   {
708     return partial_eval_logic(fo, false, rCtx);
709   }
710   else if (f->comparisonKind() == CompareConsts::VALUE_EQUAL ||
711            f->comparisonKind() == CompareConsts::GENERAL_EQUAL)
712   {
713     return partial_eval_eq(rCtx, *fo);
714   }
715   else if (fkind == FunctionConsts::FN_COUNT_1 ||
716            fkind == FunctionConsts::FN_EMPTY_1 ||
717            fkind == FunctionConsts::FN_EXISTS_1)
718   {
719     expr* arg = fo->get_arg(0);
720 
721     if (!arg->isNonDiscardable())
722     {
723       xqtref_t argType = arg->get_return_type();
724       TypeConstants::quantifier_t argQuant = argType->get_quantifier();
725       int type_cnt = argType->card();
726 
727       if (fkind == FunctionConsts::FN_COUNT_1 && type_cnt != -1)
728       {
729         return rCtx.theEM->create_const_expr(fo->get_sctx(),
730                               fo->get_loc(),
731                               xs_integer(type_cnt));
732       }
733       else if (fkind == FunctionConsts::FN_EMPTY_1)
734       {
735         if (type_cnt == 0)
736         {
737           return rCtx.theEM->create_const_expr(fo->get_sctx(), fo->get_loc(), true);
738         }
739         else if (argQuant == TypeConstants::QUANT_ONE ||
740                  argQuant == TypeConstants::QUANT_PLUS)
741         {
742           return rCtx.theEM->create_const_expr(fo->get_sctx(), fo->get_loc(), false);
743         }
744       }
745       else if (fkind == FunctionConsts::FN_EXISTS_1)
746       {
747         if (type_cnt == 0)
748         {
749           return rCtx.theEM->create_const_expr(fo->get_sctx(), fo->get_loc(), false);
750         }
751         else if (argQuant == TypeConstants::QUANT_ONE ||
752                  argQuant == TypeConstants::QUANT_PLUS)
753         {
754           return rCtx.theEM->create_const_expr(fo->get_sctx(), fo->get_loc(), true);
755         }
756       }
757     }
758 
759     if (arg->get_expr_kind() == flwor_expr_kind)
760     {
761       bool modified = false;
762       expr* newArg = partial_eval_return_clause(static_cast<flwor_expr*>(arg),
763                                                  modified,
764                                                  rCtx);
765 
766       if (newArg != arg)
767         fo->set_arg(0, newArg);
768 
769       if (modified)
770         return fo;
771     }
772 
773     return NULL;
774   }
775   else if (fkind == FunctionConsts::FN_BOOLEAN_1)
776   {
777     expr* arg = fo->get_arg(0);
778     if (!arg->isNonDiscardable())
779     {
780       xqtref_t argType = arg->get_return_type();
781       if (TypeOps::is_subtype(tm,
782                               *argType,
783                               *GENV_TYPESYSTEM.ANY_NODE_TYPE_PLUS,
784                               arg->get_loc()))
785       {
786         return rCtx.theEM->create_const_expr(fo->get_sctx(), fo->get_loc(), true);
787       }
788     }
789   }
790 
791   return NULL;
792 }
793 
794 
795 /*******************************************************************************
796   fo is a logical "and" or "or" expr. If "and" then the shortcircuit_val is
797   false, otherwise, shortcircuit_val is true.
798 ********************************************************************************/
partial_eval_logic(fo_expr * fo,bool shortcircuit_val,RewriterContext & rCtx)799 static expr* partial_eval_logic(
800     fo_expr* fo,
801     bool shortcircuit_val,
802     RewriterContext& rCtx)
803 {
804   TypeManager* tm = fo->get_type_manager();
805 
806   long nonConst1 = -1;
807   long nonConst2 = -1;
808 
809   ulong numArgs = fo->num_args();
810 
811   for (ulong i = 0; i < numArgs; ++i)
812   {
813     const expr* arg = fo->get_arg(i);
814     const const_expr* constArg = NULL;
815 
816     if ((constArg = dynamic_cast<const const_expr*>(arg)) != NULL)
817     {
818       if (constArg->get_val()->getEBV() == shortcircuit_val)
819         return rCtx.theEM->create_const_expr(fo->get_sctx(), LOC(fo), (xs_boolean)shortcircuit_val);
820     }
821     else
822     {
823       if (nonConst1 < 0)
824       {
825         nonConst1 = i;
826       }
827       else
828       {
829         nonConst2 = i;
830         break;  // no rewrite anyway
831       }
832     }
833   }
834 
835   if (nonConst1 < 0)
836   {
837     // All args are constant exprs
838     return rCtx.theEM->create_const_expr(fo->get_sctx(), LOC(fo), (xs_boolean) ! shortcircuit_val);
839   }
840 
841   if (nonConst2 < 0)
842   {
843     // Only one of the args is a constant expr. The non-const arg is pointed
844     // to by nonConst1.
845 
846     expr* arg = fo->get_arg(nonConst1);
847 
848     if (! TypeOps::is_subtype(tm,
849                               *arg->get_return_type(),
850                               *GENV_TYPESYSTEM.BOOLEAN_TYPE_ONE,
851                               arg->get_loc()))
852     {
853       arg = expr_tools::fix_annotations(rCtx.theEM->create_fo_expr(fo->get_sctx(),
854                                                     LOC(fo),
855                                                     GET_BUILTIN_FUNCTION(FN_BOOLEAN_1),
856                                                     arg));
857     }
858 
859     return arg;
860   }
861 
862   return NULL;
863 }
864 
865 
866 /*******************************************************************************
867   count(expr) = int_const
868 
869   1. if int_const < 0  --> false
870   2. if int_const == 0 --> fn:empty(expr)
871   3. if int_const == 1 --> fn:exactly-one-noraise(expr)
872   4. if int_const > 1  --> fn:exactly-one-noraise(fn:subsequence(expr, int_const, 2))
873 ********************************************************************************/
partial_eval_eq(RewriterContext & rCtx,fo_expr & fo)874 static expr* partial_eval_eq(RewriterContext& rCtx, fo_expr& fo)
875 {
876   int i;
877   fo_expr* count_expr = NULL;
878   const_expr* val_expr = NULL;
879 
880   for (i = 0; i < 2; i++)
881   {
882     if (NULL != (val_expr = dynamic_cast<const_expr*>(fo.get_arg(i))) &&
883         NULL != (count_expr = dynamic_cast<fo_expr*>(fo.get_arg(1-i))) &&
884         count_expr->get_func()->getKind() == FunctionConsts::FN_COUNT_1)
885       break;
886   }
887 
888   if (i == 2)
889     return NULL;
890 
891   RootTypeManager& rtm = GENV_TYPESYSTEM;
892 
893   TypeManager* tm = fo.get_sctx()->get_typemanager();
894 
895   store::Item* val = val_expr->get_val();
896 
897   if (TypeOps::is_subtype(tm,
898                           *tm->create_named_type(val->getType(),
899                                                  TypeConstants::QUANT_ONE,
900                                                  fo.get_loc(),
901                                                  err::XPTY0004),
902                           *rtm.INTEGER_TYPE_ONE,
903                           fo.get_loc()))
904   {
905     xs_integer ival = val->getIntegerValue();
906 
907     if (ival < 0)
908     {
909       if (!count_expr->isNonDiscardable())
910         return rCtx.theEM->create_const_expr(val_expr->get_sctx(), LOC(val_expr), false);
911     }
912     else if (ival == 0)
913     {
914       return expr_tools::fix_annotations(
915              rCtx.theEM->create_fo_expr(fo.get_sctx(), fo.get_loc(),
916                          GET_BUILTIN_FUNCTION(FN_EMPTY_1),
917                          count_expr->get_arg(0)));
918     }
919     else if (ival == 1)
920     {
921       return expr_tools::fix_annotations(
922              rCtx.theEM->create_fo_expr(fo.get_sctx(),
923                          fo.get_loc(),
924                          GET_BUILTIN_FUNCTION(OP_EXACTLY_ONE_NORAISE_1),
925                          count_expr->get_arg(0)));
926     }
927     else
928     {
929       std::vector<expr*> args(3);
930       args[0] = count_expr->get_arg(0);
931       args[1] = val_expr;
932       args[2] = rCtx.theEM->create_const_expr(val_expr->get_sctx(), LOC(val_expr), xs_integer(2));
933 
934       expr* subseq_expr = expr_tools::fix_annotations(
935       rCtx.theEM->create_fo_expr(count_expr->get_sctx(),
936                   LOC(count_expr),
937                   GET_BUILTIN_FUNCTION(OP_ZORBA_SUBSEQUENCE_INT_3),
938                   args));
939 
940       return expr_tools::fix_annotations(
941              rCtx.theEM->create_fo_expr(fo.get_sctx(),
942                          fo.get_loc(),
943                          GET_BUILTIN_FUNCTION(OP_EXACTLY_ONE_NORAISE_1),
944                          subseq_expr));
945     }
946   }
947 
948   return NULL;
949 }
950 
951 
952 /*******************************************************************************
953 
954 ********************************************************************************/
partial_eval_return_clause(flwor_expr * flworExpr,bool & modified,RewriterContext & rCtx)955 static expr* partial_eval_return_clause(flwor_expr* flworExpr,
956                                         bool& modified,
957                                         RewriterContext& rCtx)
958 {
959   expr* returnExpr = flworExpr->get_return_expr();
960 
961   if (returnExpr->get_expr_kind() == const_expr_kind ||
962       (!returnExpr->isNonDiscardable() &&
963        returnExpr->get_return_type()->card() == 1))
964   {
965     if (flworExpr->num_clauses() == 1)
966     {
967       modified = true;
968 
969       flwor_clause* c = flworExpr->get_clause(0);
970 
971       if (c->get_kind() == flwor_clause::for_clause)
972       {
973         return c->get_expr();
974       }
975       else
976       {
977         assert(c->get_kind() == flwor_clause::let_clause);
978 
979         return rCtx.theEM->create_const_expr(returnExpr->get_sctx(), returnExpr->get_loc(), 1);
980       }
981     }
982     else if (returnExpr->get_expr_kind() != const_expr_kind)
983     {
984       modified = true;
985 
986       expr* newRet =
987       rCtx.theEM->create_const_expr(returnExpr->get_sctx(), returnExpr->get_loc(), 1);
988 
989       flworExpr->set_return_expr(newRet);
990 
991       return flworExpr;
992     }
993   }
994 
995   if (returnExpr->get_expr_kind() == flwor_expr_kind)
996   {
997     expr* newRet =
998     partial_eval_return_clause(static_cast<flwor_expr*>(returnExpr),  modified, rCtx);
999 
1000     if (newRet != returnExpr)
1001     {
1002       flworExpr->set_return_expr(newRet);
1003       assert(modified);
1004     }
1005   }
1006 
1007   return flworExpr;
1008 }
1009 
1010 
1011 /*******************************************************************************
1012 
1013 ********************************************************************************/
1014 
RULE_REWRITE_PRE(InlineFunctions)1015 RULE_REWRITE_PRE(InlineFunctions)
1016 {
1017   return NULL;
1018 }
1019 
RULE_REWRITE_POST(InlineFunctions)1020 RULE_REWRITE_POST(InlineFunctions)
1021 {
1022   if (node->get_expr_kind () == fo_expr_kind)
1023   {
1024     const fo_expr* fo = static_cast<const fo_expr *> (node);
1025 
1026     const user_function* udf = dynamic_cast<const user_function *>(fo->get_func());
1027     expr* body = NULL;
1028 
1029     if (NULL != udf &&
1030         //!udf->isSequential() &&
1031         (NULL != (body = udf->getBody())) &&
1032         !udf->isExiting() &&
1033         udf->isLeaf())
1034     {
1035       const std::vector<var_expr*>& udfArgs = udf->getArgVars();
1036 
1037       expr::substitution_t subst;
1038 
1039       for (ulong i = 0; i < udfArgs.size(); ++i)
1040       {
1041         var_expr* p = udfArgs[i];
1042         subst[p] = fo->get_arg(i);
1043 
1044         if (fo->get_arg(i)->is_sequential())
1045           return NULL;
1046       }
1047 
1048       try
1049       {
1050         expr* body = udf->getBody();
1051         body = body->clone(subst);
1052         body->clear_annotations();
1053         if (rCtx.getCompilerCB()->theConfig.opt_level <= CompilerCB::config::O1)
1054         {
1055           function_trace_expr* dummy = rCtx.theEM->create_function_trace_expr(body);
1056           dummy->setFunctionName(udf->getName());
1057           dummy->setFunctionArity((unsigned int)udf->getArgVars().size());
1058           dummy->setFunctionCallLocation(node->get_loc());
1059           dummy->setFunctionLocation(udf->getLoc());
1060           return dummy;
1061         }
1062         else
1063         {
1064           return body;
1065         }
1066       }
1067       catch (...)
1068       {
1069         // TODO: this is caught here, because clone is not implemented for all expressions
1070         throw XQUERY_EXCEPTION(
1071           zerr::ZXQP0003_INTERNAL_ERROR,
1072           ERROR_PARAMS( ZED( CloneNotImplemented ) ),
1073           ERROR_LOC( udf->getLoc() )
1074         );
1075       }
1076     }
1077   }
1078 
1079   return NULL;
1080 }
1081 
1082 } // namespace zorba
1083 /* vim:set et sw=2 ts=2: */
1084