Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / xml / XPathFunctions.cpp
1 /*
2  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
3  * Copyright (C) 2006, 2009 Apple Inc.
4  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "core/xml/XPathFunctions.h"
30
31 #include "core/XMLNames.h"
32 #include "core/dom/Attr.h"
33 #include "core/dom/Element.h"
34 #include "core/dom/ProcessingInstruction.h"
35 #include "core/dom/TreeScope.h"
36 #include "core/xml/XPathUtil.h"
37 #include "core/xml/XPathValue.h"
38 #include "wtf/MathExtras.h"
39 #include "wtf/text/StringBuilder.h"
40
41 namespace blink {
42 namespace XPath {
43
44 static inline bool isWhitespace(UChar c)
45 {
46     return c == ' ' || c == '\n' || c == '\r' || c == '\t';
47 }
48
49
50 #define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
51
52 class Interval {
53 public:
54     static const int Inf = -1;
55
56     Interval();
57     Interval(int value);
58     Interval(int min, int max);
59
60     bool contains(int value) const;
61
62 private:
63     int m_min;
64     int m_max;
65 };
66
67 struct FunctionRec {
68     typedef Function *(*FactoryFn)();
69     FactoryFn factoryFn;
70     Interval args;
71 };
72
73 static HashMap<String, FunctionRec>* functionMap;
74
75 class FunLast FINAL : public Function {
76     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
77     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
78 public:
79     FunLast() { setIsContextSizeSensitive(true); }
80 };
81
82 class FunPosition FINAL : public Function {
83     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
84     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
85 public:
86     FunPosition() { setIsContextPositionSensitive(true); }
87 };
88
89 class FunCount FINAL : public Function {
90     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
91     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
92 };
93
94 class FunId FINAL : public Function {
95     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
96     virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
97 };
98
99 class FunLocalName FINAL : public Function {
100     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
101     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
102 public:
103     FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node.
104 };
105
106 class FunNamespaceURI FINAL : public Function {
107     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
108     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
109 public:
110     FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node.
111 };
112
113 class FunName FINAL : public Function {
114     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
115     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
116 public:
117     FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node.
118 };
119
120 class FunString FINAL : public Function {
121     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
122     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
123 public:
124     FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node.
125 };
126
127 class FunConcat FINAL : public Function {
128     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
129     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
130 };
131
132 class FunStartsWith FINAL : public Function {
133     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
134     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
135 };
136
137 class FunContains FINAL : public Function {
138     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
139     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
140 };
141
142 class FunSubstringBefore FINAL : public Function {
143     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
144     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
145 };
146
147 class FunSubstringAfter FINAL : public Function {
148     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
149     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
150 };
151
152 class FunSubstring FINAL : public Function {
153     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
154     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
155 };
156
157 class FunStringLength FINAL : public Function {
158     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
159     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
160 public:
161     FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node.
162 };
163
164 class FunNormalizeSpace FINAL : public Function {
165     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
166     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
167 public:
168     FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node.
169 };
170
171 class FunTranslate FINAL : public Function {
172     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
173     virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
174 };
175
176 class FunBoolean FINAL : public Function {
177     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
178     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
179 };
180
181 class FunNot FINAL : public Function {
182     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
183     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
184 };
185
186 class FunTrue FINAL : public Function {
187     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
188     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
189 };
190
191 class FunFalse FINAL : public Function {
192     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
193     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
194 };
195
196 class FunLang FINAL : public Function {
197     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
198     virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
199 public:
200     FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node.
201 };
202
203 class FunNumber FINAL : public Function {
204     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
205     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
206 public:
207     FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node.
208 };
209
210 class FunSum FINAL : public Function {
211     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
212     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
213 };
214
215 class FunFloor FINAL : public Function {
216     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
217     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
218 };
219
220 class FunCeiling FINAL : public Function {
221     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
222     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
223 };
224
225 class FunRound FINAL : public Function {
226     virtual Value evaluate(EvaluationContext&) const OVERRIDE;
227     virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
228 public:
229     static double round(double);
230 };
231
232 DEFINE_FUNCTION_CREATOR(FunLast)
233 DEFINE_FUNCTION_CREATOR(FunPosition)
234 DEFINE_FUNCTION_CREATOR(FunCount)
235 DEFINE_FUNCTION_CREATOR(FunId)
236 DEFINE_FUNCTION_CREATOR(FunLocalName)
237 DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
238 DEFINE_FUNCTION_CREATOR(FunName)
239
240 DEFINE_FUNCTION_CREATOR(FunString)
241 DEFINE_FUNCTION_CREATOR(FunConcat)
242 DEFINE_FUNCTION_CREATOR(FunStartsWith)
243 DEFINE_FUNCTION_CREATOR(FunContains)
244 DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
245 DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
246 DEFINE_FUNCTION_CREATOR(FunSubstring)
247 DEFINE_FUNCTION_CREATOR(FunStringLength)
248 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
249 DEFINE_FUNCTION_CREATOR(FunTranslate)
250
251 DEFINE_FUNCTION_CREATOR(FunBoolean)
252 DEFINE_FUNCTION_CREATOR(FunNot)
253 DEFINE_FUNCTION_CREATOR(FunTrue)
254 DEFINE_FUNCTION_CREATOR(FunFalse)
255 DEFINE_FUNCTION_CREATOR(FunLang)
256
257 DEFINE_FUNCTION_CREATOR(FunNumber)
258 DEFINE_FUNCTION_CREATOR(FunSum)
259 DEFINE_FUNCTION_CREATOR(FunFloor)
260 DEFINE_FUNCTION_CREATOR(FunCeiling)
261 DEFINE_FUNCTION_CREATOR(FunRound)
262
263 #undef DEFINE_FUNCTION_CREATOR
264
265 inline Interval::Interval()
266     : m_min(Inf), m_max(Inf)
267 {
268 }
269
270 inline Interval::Interval(int value)
271     : m_min(value), m_max(value)
272 {
273 }
274
275 inline Interval::Interval(int min, int max)
276     : m_min(min), m_max(max)
277 {
278 }
279
280 inline bool Interval::contains(int value) const
281 {
282     if (m_min == Inf && m_max == Inf)
283         return true;
284
285     if (m_min == Inf)
286         return value <= m_max;
287
288     if (m_max == Inf)
289         return value >= m_min;
290
291     return value >= m_min && value <= m_max;
292 }
293
294 void Function::setArguments(WillBeHeapVector<OwnPtrWillBeMember<Expression> >& args)
295 {
296     ASSERT(!subExprCount());
297
298     // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive.
299     if (m_name != "lang" && !args.isEmpty())
300         setIsContextNodeSensitive(false);
301
302     WillBeHeapVector<OwnPtrWillBeMember<Expression> >::iterator end = args.end();
303     for (WillBeHeapVector<OwnPtrWillBeMember<Expression> >::iterator it = args.begin(); it != end; ++it)
304         addSubExpression(it->release());
305 }
306
307 Value FunLast::evaluate(EvaluationContext& context) const
308 {
309     return context.size;
310 }
311
312 Value FunPosition::evaluate(EvaluationContext& context) const
313 {
314     return context.position;
315 }
316
317 Value FunId::evaluate(EvaluationContext& context) const
318 {
319     Value a = arg(0)->evaluate(context);
320     StringBuilder idList; // A whitespace-separated list of IDs
321
322     if (a.isNodeSet()) {
323         const NodeSet& nodes = a.toNodeSet(&context);
324         for (size_t i = 0; i < nodes.size(); ++i) {
325             String str = stringValue(nodes[i]);
326             idList.append(str);
327             idList.append(' ');
328         }
329     } else {
330         String str = a.toString();
331         idList.append(str);
332     }
333
334     TreeScope& contextScope = context.node->treeScope();
335     OwnPtrWillBeRawPtr<NodeSet> result(NodeSet::create());
336     WillBeHeapHashSet<RawPtrWillBeMember<Node> > resultSet;
337
338     unsigned startPos = 0;
339     unsigned length = idList.length();
340     while (true) {
341         while (startPos < length && isWhitespace(idList[startPos]))
342             ++startPos;
343
344         if (startPos == length)
345             break;
346
347         size_t endPos = startPos;
348         while (endPos < length && !isWhitespace(idList[endPos]))
349             ++endPos;
350
351         // If there are several nodes with the same id, id() should return the first one.
352         // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
353         Node* node = contextScope.getElementById(AtomicString(idList.substring(startPos, endPos - startPos)));
354         if (node && resultSet.add(node).isNewEntry)
355             result->append(node);
356
357         startPos = endPos;
358     }
359
360     result->markSorted(false);
361
362     return Value(result.release(), Value::adopt);
363 }
364
365 static inline String expandedNameLocalPart(Node* node)
366 {
367     // The local part of an XPath expanded-name matches DOM local name for most node types, except for namespace nodes and processing instruction nodes.
368     // But note that Blink does not support namespace nodes.
369     if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
370         return toProcessingInstruction(node)->target();
371     return node->localName().string();
372 }
373
374 static inline String expandedName(Node* node)
375 {
376     AtomicString prefix;
377
378     switch (node->nodeType()) {
379     case Node::ELEMENT_NODE:
380         prefix = toElement(node)->prefix();
381         break;
382     case Node::ATTRIBUTE_NODE:
383         prefix = toAttr(node)->prefix();
384         break;
385     default:
386         break;
387     }
388
389     return prefix.isEmpty() ? expandedNameLocalPart(node) : prefix + ":" + expandedNameLocalPart(node);
390 }
391
392 Value FunLocalName::evaluate(EvaluationContext& context) const
393 {
394     if (argCount() > 0) {
395         Value a = arg(0)->evaluate(context);
396         if (!a.isNodeSet())
397             return "";
398
399         Node* node = a.toNodeSet(&context).firstNode();
400         return node ? expandedNameLocalPart(node) : "";
401     }
402
403     return expandedNameLocalPart(context.node.get());
404 }
405
406 Value FunNamespaceURI::evaluate(EvaluationContext& context) const
407 {
408     if (argCount() > 0) {
409         Value a = arg(0)->evaluate(context);
410         if (!a.isNodeSet())
411             return "";
412
413         Node* node = a.toNodeSet(&context).firstNode();
414         return node ? node->namespaceURI().string() : "";
415     }
416
417     return context.node->namespaceURI().string();
418 }
419
420 Value FunName::evaluate(EvaluationContext& context) const
421 {
422     if (argCount() > 0) {
423         Value a = arg(0)->evaluate(context);
424         if (!a.isNodeSet())
425             return "";
426
427         Node* node = a.toNodeSet(&context).firstNode();
428         return node ? expandedName(node) : "";
429     }
430
431     return expandedName(context.node.get());
432 }
433
434 Value FunCount::evaluate(EvaluationContext& context) const
435 {
436     Value a = arg(0)->evaluate(context);
437
438     return double(a.toNodeSet(&context).size());
439 }
440
441 Value FunString::evaluate(EvaluationContext& context) const
442 {
443     if (!argCount())
444         return Value(context.node.get()).toString();
445     return arg(0)->evaluate(context).toString();
446 }
447
448 Value FunConcat::evaluate(EvaluationContext& context) const
449 {
450     StringBuilder result;
451     result.reserveCapacity(1024);
452
453     unsigned count = argCount();
454     for (unsigned i = 0; i < count; ++i) {
455         String str(arg(i)->evaluate(context).toString());
456         result.append(str);
457     }
458
459     return result.toString();
460 }
461
462 Value FunStartsWith::evaluate(EvaluationContext& context) const
463 {
464     String s1 = arg(0)->evaluate(context).toString();
465     String s2 = arg(1)->evaluate(context).toString();
466
467     if (s2.isEmpty())
468         return true;
469
470     return s1.startsWith(s2);
471 }
472
473 Value FunContains::evaluate(EvaluationContext& context) const
474 {
475     String s1 = arg(0)->evaluate(context).toString();
476     String s2 = arg(1)->evaluate(context).toString();
477
478     if (s2.isEmpty())
479         return true;
480
481     return s1.contains(s2) != 0;
482 }
483
484 Value FunSubstringBefore::evaluate(EvaluationContext& context) const
485 {
486     String s1 = arg(0)->evaluate(context).toString();
487     String s2 = arg(1)->evaluate(context).toString();
488
489     if (s2.isEmpty())
490         return "";
491
492     size_t i = s1.find(s2);
493
494     if (i == kNotFound)
495         return "";
496
497     return s1.left(i);
498 }
499
500 Value FunSubstringAfter::evaluate(EvaluationContext& context) const
501 {
502     String s1 = arg(0)->evaluate(context).toString();
503     String s2 = arg(1)->evaluate(context).toString();
504
505     size_t i = s1.find(s2);
506     if (i == kNotFound)
507         return "";
508
509     return s1.substring(i + s2.length());
510 }
511
512 Value FunSubstring::evaluate(EvaluationContext& context) const
513 {
514     String s = arg(0)->evaluate(context).toString();
515     double doublePos = arg(1)->evaluate(context).toNumber();
516     if (std::isnan(doublePos))
517         return "";
518     long pos = static_cast<long>(FunRound::round(doublePos));
519     bool haveLength = argCount() == 3;
520     long len = -1;
521     if (haveLength) {
522         double doubleLen = arg(2)->evaluate(context).toNumber();
523         if (std::isnan(doubleLen))
524             return "";
525         len = static_cast<long>(FunRound::round(doubleLen));
526     }
527
528     if (pos > long(s.length()))
529         return "";
530
531     if (pos < 1) {
532         if (haveLength) {
533             len -= 1 - pos;
534             if (len < 1)
535                 return "";
536         }
537         pos = 1;
538     }
539
540     return s.substring(pos - 1, len);
541 }
542
543 Value FunStringLength::evaluate(EvaluationContext& context) const
544 {
545     if (!argCount())
546         return Value(context.node.get()).toString().length();
547     return arg(0)->evaluate(context).toString().length();
548 }
549
550 Value FunNormalizeSpace::evaluate(EvaluationContext& context) const
551 {
552     if (!argCount()) {
553         String s = Value(context.node.get()).toString();
554         return s.simplifyWhiteSpace();
555     }
556
557     String s = arg(0)->evaluate(context).toString();
558     return s.simplifyWhiteSpace();
559 }
560
561 Value FunTranslate::evaluate(EvaluationContext& context) const
562 {
563     String s1 = arg(0)->evaluate(context).toString();
564     String s2 = arg(1)->evaluate(context).toString();
565     String s3 = arg(2)->evaluate(context).toString();
566     StringBuilder result;
567
568     for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
569         UChar ch = s1[i1];
570         size_t i2 = s2.find(ch);
571
572         if (i2 == kNotFound)
573             result.append(ch);
574         else if (i2 < s3.length())
575             result.append(s3[i2]);
576     }
577
578     return result.toString();
579 }
580
581 Value FunBoolean::evaluate(EvaluationContext& context) const
582 {
583     return arg(0)->evaluate(context).toBoolean();
584 }
585
586 Value FunNot::evaluate(EvaluationContext& context) const
587 {
588     return !arg(0)->evaluate(context).toBoolean();
589 }
590
591 Value FunTrue::evaluate(EvaluationContext&) const
592 {
593     return true;
594 }
595
596 Value FunLang::evaluate(EvaluationContext& context) const
597 {
598     String lang = arg(0)->evaluate(context).toString();
599
600     const Attribute* languageAttribute = 0;
601     Node* node = context.node.get();
602     while (node) {
603         if (node->isElementNode()) {
604             Element* element = toElement(node);
605             languageAttribute = element->attributes().find(XMLNames::langAttr);
606         }
607         if (languageAttribute)
608             break;
609         node = node->parentNode();
610     }
611
612     if (!languageAttribute)
613         return false;
614
615     String langValue = languageAttribute->value();
616     while (true) {
617         if (equalIgnoringCase(langValue, lang))
618             return true;
619
620         // Remove suffixes one by one.
621         size_t index = langValue.reverseFind('-');
622         if (index == kNotFound)
623             break;
624         langValue = langValue.left(index);
625     }
626
627     return false;
628 }
629
630 Value FunFalse::evaluate(EvaluationContext&) const
631 {
632     return false;
633 }
634
635 Value FunNumber::evaluate(EvaluationContext& context) const
636 {
637     if (!argCount())
638         return Value(context.node.get()).toNumber();
639     return arg(0)->evaluate(context).toNumber();
640 }
641
642 Value FunSum::evaluate(EvaluationContext& context) const
643 {
644     Value a = arg(0)->evaluate(context);
645     if (!a.isNodeSet())
646         return 0.0;
647
648     double sum = 0.0;
649     const NodeSet& nodes = a.toNodeSet(&context);
650     // To be really compliant, we should sort the node-set, as floating point addition is not associative.
651     // However, this is unlikely to ever become a practical issue, and sorting is slow.
652
653     for (unsigned i = 0; i < nodes.size(); i++)
654         sum += Value(stringValue(nodes[i])).toNumber();
655
656     return sum;
657 }
658
659 Value FunFloor::evaluate(EvaluationContext& context) const
660 {
661     return floor(arg(0)->evaluate(context).toNumber());
662 }
663
664 Value FunCeiling::evaluate(EvaluationContext& context) const
665 {
666     return ceil(arg(0)->evaluate(context).toNumber());
667 }
668
669 double FunRound::round(double val)
670 {
671     if (!std::isnan(val) && !std::isinf(val)) {
672         if (std::signbit(val) && val >= -0.5)
673             val *= 0; // negative zero
674         else
675             val = floor(val + 0.5);
676     }
677     return val;
678 }
679
680 Value FunRound::evaluate(EvaluationContext& context) const
681 {
682     return round(arg(0)->evaluate(context).toNumber());
683 }
684
685 struct FunctionMapping {
686     const char* name;
687     FunctionRec function;
688 };
689
690 static void createFunctionMap()
691 {
692     static const FunctionMapping functions[] = {
693         { "boolean", { &createFunBoolean, 1 } },
694         { "ceiling", { &createFunCeiling, 1 } },
695         { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
696         { "contains", { &createFunContains, 2 } },
697         { "count", { &createFunCount, 1 } },
698         { "false", { &createFunFalse, 0 } },
699         { "floor", { &createFunFloor, 1 } },
700         { "id", { &createFunId, 1 } },
701         { "lang", { &createFunLang, 1 } },
702         { "last", { &createFunLast, 0 } },
703         { "local-name", { &createFunLocalName, Interval(0, 1) } },
704         { "name", { &createFunName, Interval(0, 1) } },
705         { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
706         { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
707         { "not", { &createFunNot, 1 } },
708         { "number", { &createFunNumber, Interval(0, 1) } },
709         { "position", { &createFunPosition, 0 } },
710         { "round", { &createFunRound, 1 } },
711         { "starts-with", { &createFunStartsWith, 2 } },
712         { "string", { &createFunString, Interval(0, 1) } },
713         { "string-length", { &createFunStringLength, Interval(0, 1) } },
714         { "substring", { &createFunSubstring, Interval(2, 3) } },
715         { "substring-after", { &createFunSubstringAfter, 2 } },
716         { "substring-before", { &createFunSubstringBefore, 2 } },
717         { "sum", { &createFunSum, 1 } },
718         { "translate", { &createFunTranslate, 3 } },
719         { "true", { &createFunTrue, 0 } },
720     };
721
722     functionMap = new HashMap<String, FunctionRec>;
723     for (size_t i = 0; i < WTF_ARRAY_LENGTH(functions); ++i)
724         functionMap->set(functions[i].name, functions[i].function);
725 }
726
727
728 Function* createFunction(const String& name)
729 {
730     WillBeHeapVector<OwnPtrWillBeMember<Expression> > args;
731     return createFunction(name, args);
732 }
733
734 Function* createFunction(const String& name, WillBeHeapVector<OwnPtrWillBeMember<Expression> >& args)
735 {
736     if (!functionMap)
737         createFunctionMap();
738
739     HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name);
740     FunctionRec* functionRec = 0;
741
742     if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->value)->args.contains(args.size()))
743         return 0;
744
745     Function* function = functionRec->factoryFn();
746     function->setArguments(args);
747     function->setName(name);
748     return function;
749 }
750
751 }
752 }