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 <vector>
19 
20 #include "compiler/expression/fo_expr.h"
21 #include "compiler/expression/expr_visitor.h"
22 
23 #include "compiler/api/compilercb.h"
24 
25 #include "context/static_context.h"
26 
27 #include "functions/library.h"
28 #include "functions/function.h"
29 #include "functions/udf.h"
30 
31 #include "diagnostics/assert.h"
32 #include "diagnostics/util_macros.h"
33 #include "diagnostics/xquery_diagnostics.h"
34 
35 namespace zorba
36 {
37 
38 
accept(expr_visitor & v)39 void fo_expr::accept(expr_visitor& v)
40 {
41   if (v.begin_visit(*this))
42   {
43     accept_children(v);
44   }
45 
46   v.end_visit(*this);
47 }
48 
49 
50 
51 /*******************************************************************************
52   first-order expressions. Represents function invocations as well as:
53 
54   OrExpr, AndExpr, ComparisonExpr, RangeExpr, AdditiveExpr, MultiplicativeExpr,
55   UnionExpr, and IntersectExceptExpr.
56 ********************************************************************************/
57 
create_seq(CompilerCB * ccb,static_context * sctx,const QueryLoc & loc)58 fo_expr* fo_expr::create_seq(CompilerCB* ccb, static_context* sctx, const QueryLoc& loc)
59 {
60   function* f = BuiltinFunctionLibrary::getFunction(FunctionConsts::OP_CONCATENATE_N);
61 
62   std::auto_ptr<fo_expr> fo(ccb->theEM->create_fo_expr(sctx, loc, f));
63 
64   return fo.release();
65 }
66 
67 
fo_expr(CompilerCB * ccb,static_context * sctx,const QueryLoc & loc,const function * f)68 fo_expr::fo_expr(
69     CompilerCB* ccb,
70     static_context* sctx,
71     const QueryLoc& loc,
72     const function* f)
73   :
74   expr(ccb, sctx, loc, fo_expr_kind),
75   theFunction(const_cast<function*>(f))
76 {
77   // This method is private and it is to be used only by the clone method
78   assert(f != NULL);
79   theScriptingKind = VACUOUS_EXPR;
80 }
81 
82 
fo_expr(CompilerCB * ccb,static_context * sctx,const QueryLoc & loc,const function * f,expr * arg)83 fo_expr::fo_expr(
84     CompilerCB* ccb,
85     static_context* sctx,
86     const QueryLoc& loc,
87     const function* f,
88     expr* arg)
89   :
90   expr(ccb, sctx, loc, fo_expr_kind),
91   theFunction(const_cast<function*>(f))
92 {
93   assert(f != NULL);
94   theArgs.resize(1);
95   theArgs[0] = arg;
96 
97   compute_scripting_kind();
98 }
99 
100 
fo_expr(CompilerCB * ccb,static_context * sctx,const QueryLoc & loc,const function * f,expr * arg1,expr * arg2)101 fo_expr::fo_expr(
102     CompilerCB* ccb,
103     static_context* sctx,
104     const QueryLoc& loc,
105     const function* f,
106     expr* arg1,
107     expr* arg2)
108   :
109   expr(ccb, sctx, loc, fo_expr_kind),
110   theFunction(const_cast<function*>(f))
111 {
112   assert(f != NULL);
113   theArgs.resize(2);
114   theArgs[0] = arg1;
115   theArgs[1] = arg2;
116 
117   compute_scripting_kind();
118 }
119 
120 
fo_expr(CompilerCB * ccb,static_context * sctx,const QueryLoc & loc,const function * f,const std::vector<expr * > & args)121 fo_expr::fo_expr(
122     CompilerCB* ccb,
123     static_context* sctx,
124     const QueryLoc& loc,
125     const function* f,
126     const std::vector<expr*>& args)
127   :
128   expr(ccb, sctx, loc, fo_expr_kind),
129   theArgs(args),
130   theFunction(const_cast<function*>(f))
131 {
132   assert(f != NULL);
133   compute_scripting_kind();
134 }
135 
136 
get_signature() const137 const signature& fo_expr::get_signature() const
138 {
139   return theFunction->getSignature();
140 }
141 
142 
get_fname() const143 const store::Item* fo_expr::get_fname() const
144 {
145   return theFunction->getName();
146 }
147 
148 
add_arg(expr * e)149 void fo_expr::add_arg(expr* e)
150 {
151   theArgs.push_back(e);
152   compute_scripting_kind();
153 }
154 
155 
add_args(const std::vector<expr * > & args)156 void fo_expr::add_args(const std::vector<expr*>& args)
157 {
158   theArgs.insert(theArgs.end(), args.begin(), args.end());
159   compute_scripting_kind();
160 }
161 
162 
remove_arg(csize i)163 void fo_expr::remove_arg(csize i)
164 {
165   theArgs.erase(theArgs.begin() + i);
166   compute_scripting_kind();
167 }
168 
169 
compute_scripting_kind()170 void fo_expr::compute_scripting_kind()
171 {
172   const function* func = get_func();
173   csize numArgs = num_args();
174 
175   switch (func->getKind())
176   {
177   case FunctionConsts::OP_CONCATENATE_N:
178   {
179     bool vacuous = true;
180 
181     theScriptingKind = VACUOUS_EXPR;
182 
183     for (csize i = 0; i < numArgs; ++i)
184     {
185       if (theArgs[i] == NULL)
186         continue;
187 
188       short argKind = theArgs[i]->get_scripting_detail();
189 
190       if (argKind == VACUOUS_EXPR)
191         continue;
192 
193       vacuous = false;
194 
195       if (!theSctx->is_feature_set(feature::scripting))
196       {
197         if (is_updating() && !(argKind & UPDATING_EXPR) && argKind != VACUOUS_EXPR)
198         {
199           RAISE_ERROR(err::XUST0001, theArgs[i]->get_loc(),
200           ERROR_PARAMS(ZED(XUST0001_CONCAT)));
201         }
202 
203         if (i > 0 && !is_updating() && !is_vacuous() && (argKind & UPDATING_EXPR))
204         {
205           RAISE_ERROR(err::XUST0001, theArgs[i]->get_loc(),
206           ERROR_PARAMS(ZED(XUST0001_CONCAT)));
207         }
208       }
209 
210       theScriptingKind |= argKind;
211     }
212 
213     if (!vacuous)
214       theScriptingKind &= ~VACUOUS_EXPR;
215 
216     if (theScriptingKind & UPDATING_EXPR)
217       theScriptingKind &= ~SIMPLE_EXPR;
218 
219     if (is_sequential(theScriptingKind))
220       theScriptingKind &= ~SIMPLE_EXPR;
221 
222     checkScriptingKind();
223 
224     break;
225   }
226   case FunctionConsts::OP_HOIST_1:
227   case FunctionConsts::OP_UNHOIST_1:
228   {
229     theScriptingKind = theArgs[0]->get_scripting_detail();
230     break;
231   }
232   default:
233   {
234     theScriptingKind = func->getScriptingKind();
235 
236     bool vacuous = (theScriptingKind == VACUOUS_EXPR);
237 
238     for (csize i = 0; i < numArgs; ++i)
239     {
240       if (theArgs[i] == NULL)
241         continue;
242 
243       expr* arg = theArgs[i];
244 
245       if (arg->is_updating())
246       {
247         RAISE_ERROR(err::XUST0001, theArgs[i]->get_loc(),
248         ERROR_PARAMS(ZED(XUST0001_Generic)));
249       }
250 
251       short argKind = arg->get_scripting_detail();
252 
253       if (arg->is_sequential())
254       {
255         vacuous = false;
256 
257         theScriptingKind |= argKind;
258       }
259     }
260 
261     if (!vacuous)
262       theScriptingKind &= ~VACUOUS_EXPR;
263 
264     if (theScriptingKind & UPDATING_EXPR)
265       theScriptingKind &= ~SIMPLE_EXPR;
266 
267     if (is_sequential(theScriptingKind))
268       theScriptingKind &= ~SIMPLE_EXPR;
269 
270     checkScriptingKind();
271   }
272   }
273 }
274 
275 
cloneImpl(substitution_t & subst) const276 expr* fo_expr::cloneImpl(substitution_t& subst) const
277 {
278   if (get_func()->getKind() == FunctionConsts::STATIC_COLLECTIONS_DML_COLLECTION_1)
279   {
280     expr::subst_iter_t i = subst.find(this);
281 
282     if (i != subst.end())
283       return i->second;
284   }
285 
286   std::auto_ptr<fo_expr> fo(theCCB->theEM->create_fo_expr(theSctx,
287                                                           get_loc(),
288                                                           get_func()));
289 
290   for (csize i = 0; i < theArgs.size(); ++i)
291     fo->theArgs.push_back(theArgs[i]->clone(subst));
292 
293   fo->theScriptingKind  = theScriptingKind;
294 
295   return fo.release();
296 }
297 
298 
299 }
300 
301 /* vim:set et sw=2 ts=2: */
302