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 "annotations/annotations.h"
19 
20 #include "store/api/item.h"
21 #include "store/api/item_factory.h"
22 
23 #include "compiler/expression/expr.h"
24 
25 #include "diagnostics/assert.h"
26 #include "diagnostics/util_macros.h"
27 
28 #include "system/globalenv.h"
29 
30 #include "zorbaserialization/serialize_template_types.h"
31 #include "zorbaserialization/serialize_zorba_types.h"
32 
33 namespace zorba {
34 
35 SERIALIZABLE_CLASS_VERSIONS(AnnotationInternal)
36 
37 SERIALIZABLE_CLASS_VERSIONS(AnnotationList)
38 
39 
40 std::vector<store::Item_t>
41 AnnotationInternal::theAnnotId2NameMap;
42 
43 ItemHandleHashMap<AnnotationInternal::AnnotationId>
44 AnnotationInternal::theAnnotName2IdMap(0, NULL, 64, false);
45 
46 std::vector<AnnotationInternal::RuleBitSet>
47 AnnotationInternal::theRuleSet;
48 
49 
50 /*******************************************************************************
51   Static method, called from GlobalEnvironment::init()
52 ********************************************************************************/
createBuiltIn()53 void AnnotationInternal::createBuiltIn()
54 {
55   store::Item_t qname;
56   AnnotationId id;
57 
58   theAnnotId2NameMap.resize(zann_end);
59 
60   //
61   // W3C annotations
62   //
63   GENV_ITEMFACTORY->createQName(qname, static_context::W3C_FN_NS, "fn", "public");
64   id = fn_public;
65   theAnnotId2NameMap[id] = qname;
66   theAnnotName2IdMap.insert(qname, id);
67 
68   GENV_ITEMFACTORY->createQName(qname, static_context::W3C_FN_NS, "fn", "private");
69   id = fn_private;
70   theAnnotId2NameMap[id] = qname;
71   theAnnotName2IdMap.insert(qname, id);
72 
73 #define ZANN(a, b)                                                     \
74   GENV_ITEMFACTORY->createQName(qname, ZORBA_ANNOTATIONS_NS, "", #a);  \
75   id = zann_##b;                                                       \
76   theAnnotId2NameMap[id] = qname;                                      \
77   theAnnotName2IdMap.insert(qname, id);
78 
79 
80   //
81   // Zorba annotations - deterministic/nondeterministic
82   //
83   ZANN(deterministic, deterministic);
84   ZANN(nondeterministic, nondeterministic);
85 
86   //
87   // Zorba annotations - xquery scripting
88   //
89   ZANN(assignable, assignable);
90   ZANN(nonassignable, nonassignable);
91 
92   ZANN(sequential, sequential);
93   ZANN(nonsequential, nonsequential);
94 
95   //
96   // Zorba annotations - optimizer
97   //
98   ZANN(propagates-input-nodes, propagates_input_nodes);
99   ZANN(must-copy-input-nodes, must_copy_input_nodes);
100 
101   //
102   // Zorba annotations - misc
103   //
104   ZANN(variadic, variadic);
105 
106   ZANN(streamable, streamable);
107 
108   ZANN(cache, cache);
109   ZANN(no-cache, nocache);
110 
111   //
112   // Zorba annotations - xqddf
113   //
114   ZANN(unique, unique);
115   ZANN(nonunique, nonunique);
116 
117   ZANN(value-equality, value_equality);
118   ZANN(general-equality, general_equality);
119   ZANN(value-range, value_range);
120   ZANN(general-range, general_range);
121 
122   ZANN(automatic, automatic);
123   ZANN(manual, manual);
124 
125   ZANN(mutable, mutable);
126   ZANN(queue, queue);
127   ZANN(append-only, append_only);
128   ZANN(const, const);
129 
130   ZANN(ordered, ordered);
131   ZANN(unordered, unordered);
132 
133   ZANN(read-only-nodes, read_only_nodes);
134   ZANN(mutable-nodes, mutable_nodes);
135 
136 #undef ZANN
137 
138   // create a set of rules to detect conflicts between annotations
139 #define ZANN(a) \
140   ( 1 << static_cast<uint64_t>(AnnotationInternal::a) )
141 
142   theRuleSet.push_back(
143        ZANN(zann_unique) |
144        ZANN(zann_nonunique));
145 
146   theRuleSet.push_back(
147       ZANN(zann_value_equality) |
148       ZANN(zann_general_equality) |
149       ZANN(zann_value_range) |
150       ZANN(zann_general_range));
151 
152   theRuleSet.push_back(
153       ZANN(zann_automatic) |
154       ZANN(zann_manual));
155 
156   theRuleSet.push_back(
157       ZANN(zann_mutable) |
158       ZANN(zann_queue) |
159       ZANN(zann_append_only) |
160       ZANN(zann_const));
161 
162   theRuleSet.push_back(
163       ZANN(zann_ordered) |
164       ZANN(zann_unordered));
165 
166   theRuleSet.push_back(
167       ZANN(zann_assignable) |
168       ZANN(zann_nonassignable));
169 
170   theRuleSet.push_back(
171       ZANN(zann_deterministic) |
172       ZANN(zann_nondeterministic));
173 
174   theRuleSet.push_back(
175       ZANN(zann_sequential) |
176       ZANN(zann_nonsequential));
177 
178   theRuleSet.push_back(
179       ZANN(zann_cache) |
180       ZANN(zann_nocache));
181 
182   theRuleSet.push_back(
183       ZANN(fn_private) |
184       ZANN(fn_public));
185 
186   theRuleSet.push_back(
187       ZANN(zann_unordered) |
188       ZANN(zann_queue));
189 
190   theRuleSet.push_back(
191       ZANN(zann_unordered) |
192       ZANN(zann_append_only));
193 
194   theRuleSet.push_back(
195       ZANN(zann_queue) |
196       ZANN(zann_append_only));
197 
198   theRuleSet.push_back(
199       ZANN(zann_read_only_nodes) |
200       ZANN(zann_mutable_nodes));
201 #undef ZANN
202 }
203 
204 
205 /*******************************************************************************
206   Static method, called from GlobalEnvironment::destroy()
207 ********************************************************************************/
destroyBuiltIn()208 void AnnotationInternal::destroyBuiltIn()
209 {
210   theAnnotId2NameMap.clear();
211   theAnnotName2IdMap.clear();
212 }
213 
214 
215 /*******************************************************************************
216 
217 ********************************************************************************/
lookup(const store::Item_t & qname)218 AnnotationInternal::AnnotationId AnnotationInternal::lookup(
219     const store::Item_t& qname)
220 {
221   ItemHandleHashMap<AnnotationId>::iterator ite = theAnnotName2IdMap.find(qname);
222 
223   if (ite == theAnnotName2IdMap.end())
224     return zann_end;
225 
226   return (*ite).second;
227 }
228 
229 
230 /*******************************************************************************
231 
232 ********************************************************************************/
lookup(AnnotationInternal::AnnotationId id)233 store::Item* AnnotationInternal::lookup(AnnotationInternal::AnnotationId id)
234 {
235   assert(id < zann_end);
236   assert(id < theAnnotId2NameMap.size());
237 
238   return theAnnotId2NameMap[id].getp();
239 }
240 
241 
242 /*******************************************************************************
243 
244 ********************************************************************************/
AnnotationInternal(const store::Item_t & qname)245 AnnotationInternal::AnnotationInternal(const store::Item_t& qname)
246   :
247   theId(zann_end),
248   theQName(qname)
249 {
250   ItemHandleHashMap<AnnotationId>::iterator ite = theAnnotName2IdMap.find(qname);
251   if (ite != theAnnotName2IdMap.end())
252     theId = (*ite).second;
253 }
254 
255 
256 /*******************************************************************************
257 
258 ********************************************************************************/
AnnotationInternal(const store::Item_t & qname,std::vector<store::Item_t> & literals)259 AnnotationInternal::AnnotationInternal(
260   const store::Item_t& qname,
261   std::vector<store::Item_t>& literals)
262   :
263   theId(zann_end),
264   theQName(qname)
265 {
266   theLiterals.swap(literals);
267 
268   ItemHandleHashMap<AnnotationId>::iterator ite = theAnnotName2IdMap.find(qname);
269   if (ite != theAnnotName2IdMap.end())
270     theId = (*ite).second;
271 }
272 
273 
274 /*******************************************************************************
275 
276 ********************************************************************************/
serialize(::zorba::serialization::Archiver & ar)277 void AnnotationInternal::serialize(::zorba::serialization::Archiver& ar)
278 {
279   SERIALIZE_ENUM(AnnotationId, theId);
280   ar & theQName;
281   ar & theLiterals;
282 }
283 
284 
285 /*******************************************************************************
286 
287 ********************************************************************************/
getQName() const288 const store::Item* AnnotationInternal::getQName() const
289 {
290   return theQName.getp();
291 }
292 
293 
294 /*******************************************************************************
295 
296 ********************************************************************************/
getNumLiterals() const297 csize AnnotationInternal::getNumLiterals() const
298 {
299   return theLiterals.size();
300 }
301 
302 
303 /*******************************************************************************
304 
305 ********************************************************************************/
getLiteral(csize index) const306 store::Item* AnnotationInternal::getLiteral(csize index) const
307 {
308   if (index < theLiterals.size())
309     return theLiterals[index].getp();
310   else
311     return NULL;
312 }
313 
314 
315 /*******************************************************************************
316 
317 ********************************************************************************/
AnnotationList()318 AnnotationList::AnnotationList()
319 {
320 }
321 
322 
323 /*******************************************************************************
324 
325 ********************************************************************************/
~AnnotationList()326 AnnotationList::~AnnotationList()
327 {
328 }
329 
330 
331 /*******************************************************************************
332 
333 ********************************************************************************/
serialize(::zorba::serialization::Archiver & ar)334 void AnnotationList::serialize(::zorba::serialization::Archiver& ar)
335 {
336   ar & theAnnotationList;
337 }
338 
339 
340 /*******************************************************************************
341 
342 ********************************************************************************/
get(csize index) const343 AnnotationInternal* AnnotationList::get(csize index) const
344 {
345   if (index < theAnnotationList.size())
346     return theAnnotationList[index].getp();
347   else
348     return NULL;
349 }
350 
351 
352 /*******************************************************************************
353 
354 ********************************************************************************/
get(AnnotationInternal::AnnotationId id) const355 AnnotationInternal* AnnotationList::get(AnnotationInternal::AnnotationId id) const
356 {
357   for (ListConstIter_t ite = theAnnotationList.begin();
358        ite != theAnnotationList.end();
359        ++ite)
360   {
361     if ((*ite)->getId() == id)
362       return (*ite).getp();
363   }
364 
365   return NULL;
366 }
367 
368 
369 /*******************************************************************************
370 
371 ********************************************************************************/
contains(AnnotationInternal::AnnotationId id) const372 bool AnnotationList::contains(AnnotationInternal::AnnotationId id) const
373 {
374   return (get(id) != NULL);
375 }
376 
377 
378 /*******************************************************************************
379 
380 ********************************************************************************/
push_back(const store::Item_t & qname,const std::vector<const_expr * > & literals)381 void AnnotationList::push_back(
382     const store::Item_t& qname,
383     const std::vector<const_expr* >& literals)
384 {
385   std::vector<store::Item_t> lLiterals;
386 
387   for (std::vector<const_expr* >::const_iterator it = literals.begin();
388        it != literals.end();
389        ++it)
390   {
391     lLiterals.push_back((*it)->get_val());
392   }
393 
394   theAnnotationList.push_back(new AnnotationInternal(qname, lLiterals));
395 }
396 
397 
398 /*******************************************************************************
399   Called from translator::end_visit(const AnnotationListParsenode& v, void*)
400 ********************************************************************************/
checkConflictingDeclarations(const QueryLoc & loc) const401 void AnnotationList::checkConflictingDeclarations(const QueryLoc& loc) const
402 {
403   // make sure we don't have more annotations then max 64 bit
404   assert(AnnotationInternal::zann_end < 64);
405 
406   RuleBitSet lCurrAnn;
407 
408   // mark and detect duplicates
409   for (ListConstIter_t ite = theAnnotationList.begin();
410        ite != theAnnotationList.end();
411        ++ite)
412   {
413     const store::Item* qname = (*ite)->getQName();
414     AnnotationId id = (*ite)->getId();
415 
416     // detect duplicate annotations (if we "know" them)
417     if (id != AnnotationInternal::zann_end && lCurrAnn.test(id))
418     {
419       RAISE_ERROR(err::XQST0106, loc,
420       ERROR_PARAMS(qname->getStringValue(), ZED(XQST0106_THE_SAME)));
421     }
422 
423     lCurrAnn.set(id);
424   }
425 
426   // check rules
427   std::vector<RuleBitSet>::const_iterator ite = AnnotationInternal::theRuleSet.begin();
428   std::vector<RuleBitSet>::const_iterator end = AnnotationInternal::theRuleSet.end();
429 
430   for (; ite != end; ++ite)
431   {
432     const RuleBitSet& lCurrSet = *ite;
433 
434     if ((lCurrAnn & lCurrSet).count() >  1)
435     {
436       // build error string to return set of conflicting annotations
437       std::ostringstream lProblems;
438       for (csize i = 0, j = 0; i < AnnotationInternal::zann_end; ++i)
439       {
440         if (lCurrSet.test(i))
441         {
442           AnnotationId id = static_cast<AnnotationId>(i);
443 
444           lProblems << AnnotationInternal::lookup(id)->getStringValue()
445                     << ((j == lCurrSet.count() - 1) ? "" : ", ");
446           ++j;
447         }
448       }
449 
450       RAISE_ERROR(err::XQST0106, loc,
451       ERROR_PARAMS(lProblems.str(), ZED(XQST0106_CONFLICTING)));
452     }
453   }
454 }
455 
456 
457 } /* namespace zorba */
458 /* vim:set et sw=2 ts=2: */
459