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