2006-05-08  Anders Carlsson  <acarlsson@apple.com>

        Reviewed by Darin, Eric and Maciej.

        http://bugzilla.opendarwin.org/show_bug.cgi?id=6638
        Support Mozilla's XPathEvaluator object.
        
        * DerivedSources.make:
        Generate XPath grammar, and JavaScript wrappers.
        
        * WebCore.xcodeproj/project.pbxproj:
        Add new files to project
        
        * bindings/js/kjs_binding.cpp:
        (KJS::):
        (KJS::setDOMException):
        Handle setting XPath exceptions.
        
        * bindings/objc/DOM.mm:
        Just return nil for now when trying to create a wrapper for 
        XPath namespace nodes.

        * bindings/scripts/CodeGeneratorJS.pm:
        Add XPath types. Also add a "CanBeConstructed" extended attribute
        for interfaces that can be constructed directly.
        
        * bridge/mac/WebCorePageBridge.mm:
        (initializeLoggingChannelsIfNecessary):
        Initialize LogXPath channel.
        
        * dom/DOMImplementation.cpp:
        (WebCore::DOMImplementation::hasFeature):
        Support "xpath" version "3.0".
        
        * dom/Document.cpp:
        (WebCore::Document::Document):
        
        (WebCore::Document::importNode):
        Ignore XPath namespace nodes.
        
        (WebCore::Document::createExpression):
        (WebCore::Document::createNSResolver):
        (WebCore::Document::evaluate):
        New functions which call down to a lazily created XPathEvaluator.

        * dom/Document.h:
        Add function declarations.
        
        * dom/Document.idl:
        Add XPath methods.
        
        * dom/Node.h:
        (WebCore::Node::):
        Add XPATH_NAMESPACE_NODE type.
        
        * editing/markup.cpp:
        (WebCore::startMarkup):
        Ignore XPath namespace nodes.
        
        * page/DOMWindow.idl:
        Add constructors for XPathEvaluator and XPathResult.
        
        * platform/Logging.cpp:
        * platform/Logging.h:
        Add XPath log channel

        * xpath: Added.
        * xpath/XPathEvaluator.cpp: Added.
        (WebCore::XPathEvaluator::createExpression):
        (WebCore::XPathEvaluator::createNSResolver):
        (WebCore::XPathEvaluator::evaluate):
        * xpath/XPathEvaluator.h: Added.
        (WebCore::):
        * xpath/XPathEvaluator.idl: Added.
        * xpath/XPathExpression.cpp: Added.
        (WebCore::XPathExpression::createExpression):
        (WebCore::XPathExpression::~XPathExpression):
        (WebCore::XPathExpression::evaluate):
        * xpath/XPathExpression.h: Added.
        * xpath/XPathExpression.idl: Added.
        * xpath/XPathNSResolver.cpp: Added.
        (WebCore::XPathNSResolver::XPathNSResolver):
        (WebCore::XPathNSResolver::lookupNamespaceURI):
        * xpath/XPathNSResolver.h: Added.
        * xpath/XPathNSResolver.idl: Added.
        * xpath/XPathNamespace.cpp: Added.
        (WebCore::XPathNamespace::XPathNamespace):
        (WebCore::XPathNamespace::~XPathNamespace):
        (WebCore::XPathNamespace::ownerDocument):
        (WebCore::XPathNamespace::ownerElement):
        (WebCore::XPathNamespace::prefix):
        (WebCore::XPathNamespace::nodeName):
        (WebCore::XPathNamespace::nodeValue):
        (WebCore::XPathNamespace::namespaceURI):
        (WebCore::XPathNamespace::nodeType):
        * xpath/XPathNamespace.h: Added.
        * xpath/XPathResult.cpp: Added.
        (WebCore::InvalidatingEventListener::InvalidatingEventListener):
        (WebCore::InvalidatingEventListener::handleEvent):
        (WebCore::XPathResult::XPathResult):
        (WebCore::XPathResult::~XPathResult):
        (WebCore::XPathResult::convertTo):
        (WebCore::XPathResult::resultType):
        (WebCore::XPathResult::numberValue):
        (WebCore::XPathResult::stringValue):
        (WebCore::XPathResult::booleanValue):
        (WebCore::XPathResult::singleNodeValue):
        (WebCore::XPathResult::invalidateIteratorState):
        (WebCore::XPathResult::invalidIteratorState):
        (WebCore::XPathResult::snapshotLength):
        (WebCore::XPathResult::iterateNext):
        (WebCore::XPathResult::snapshotItem):
        * xpath/XPathResult.h: Added.
        (WebCore::XPathResult::):
        * xpath/XPathResult.idl: Added.
        * xpath/impl: Added.
        * xpath/impl/XPathExpressionNode.cpp: Added.
        (WebCore::XPath::Expression::evaluationContext):
        (WebCore::XPath::Expression::Expression):
        (WebCore::XPath::Expression::~Expression):
        (WebCore::XPath::Expression::evaluate):
        (WebCore::XPath::Expression::addSubExpression):
        (WebCore::XPath::Expression::optimize):
        (WebCore::XPath::Expression::subExprCount):
        (WebCore::XPath::Expression::subExpr):
        (WebCore::XPath::Expression::isConstant):
        * xpath/impl/XPathExpressionNode.h: Added.
        (WebCore::XPath::EvaluationContext::EvaluationContext):
        * xpath/impl/XPathFunctions.cpp: Added.
        (WebCore::XPath::Interval::Interval):
        (WebCore::XPath::Interval::contains):
        (WebCore::XPath::Interval::asString):
        (WebCore::XPath::Function::setArguments):
        (WebCore::XPath::Function::setName):
        (WebCore::XPath::Function::arg):
        (WebCore::XPath::Function::argCount):
        (WebCore::XPath::Function::name):
        (WebCore::XPath::FunLast::doEvaluate):
        (WebCore::XPath::FunLast::isConstant):
        (WebCore::XPath::FunPosition::doEvaluate):
        (WebCore::XPath::FunPosition::isConstant):
        (WebCore::XPath::FunLocalName::isConstant):
        (WebCore::XPath::FunLocalName::doEvaluate):
        (WebCore::XPath::FunNamespaceURI::isConstant):
        (WebCore::XPath::FunNamespaceURI::doEvaluate):
        (WebCore::XPath::FunName::isConstant):
        (WebCore::XPath::FunName::doEvaluate):
        (WebCore::XPath::FunCount::doEvaluate):
        (WebCore::XPath::FunCount::isConstant):
        (WebCore::XPath::FunString::doEvaluate):
        (WebCore::XPath::FunConcat::doEvaluate):
        (WebCore::XPath::FunStartsWith::doEvaluate):
        (WebCore::XPath::FunContains::doEvaluate):
        (WebCore::XPath::FunSubstringBefore::doEvaluate):
        (WebCore::XPath::FunSubstringAfter::doEvaluate):
        (WebCore::XPath::FunSubstring::doEvaluate):
        (WebCore::XPath::FunStringLength::doEvaluate):
        (WebCore::XPath::FunNormalizeSpace::doEvaluate):
        (WebCore::XPath::FunTranslate::doEvaluate):
        (WebCore::XPath::FunBoolean::doEvaluate):
        (WebCore::XPath::FunNot::doEvaluate):
        (WebCore::XPath::FunTrue::doEvaluate):
        (WebCore::XPath::FunTrue::isConstant):
        (WebCore::XPath::FunLang::doEvaluate):
        (WebCore::XPath::FunLang::isConstant):
        (WebCore::XPath::FunFalse::doEvaluate):
        (WebCore::XPath::FunFalse::isConstant):
        (WebCore::XPath::FunNumber::doEvaluate):
        (WebCore::XPath::FunSum::doEvaluate):
        (WebCore::XPath::FunFloor::doEvaluate):
        (WebCore::XPath::FunCeiling::doEvaluate):
        (WebCore::XPath::FunRound::doEvaluate):
        (WebCore::XPath::FunctionLibrary::self):
        (WebCore::XPath::FunctionLibrary::FunctionLibrary):
        (WebCore::XPath::FunctionLibrary::createFunction):
        * xpath/impl/XPathFunctions.h: Added.
        * xpath/impl/XPathGrammar.y: Added.
        * xpath/impl/XPathParser.cpp: Added.
        (WebCore::XPath::):
        (WebCore::XPath::Parser::charCat):
        (WebCore::XPath::Parser::isAxisName):
        (WebCore::XPath::Parser::isNodeTypeName):
        (WebCore::XPath::Parser::isOperatorContext):
        (WebCore::XPath::Parser::skipWS):
        (WebCore::XPath::Parser::makeTokenAndAdvance):
        (WebCore::XPath::Parser::makeIntTokenAndAdvance):
        (WebCore::XPath::Parser::peekAheadHelper):
        (WebCore::XPath::Parser::peekCurHelper):
        (WebCore::XPath::Parser::lexString):
        (WebCore::XPath::Parser::lexNumber):
        (WebCore::XPath::Parser::lexNCName):
        (WebCore::XPath::Parser::lexQName):
        (WebCore::XPath::Parser::nextTokenInternal):
        (WebCore::XPath::Parser::nextToken):
        (WebCore::XPath::Parser::Parser):
        (WebCore::XPath::Parser::reset):
        (WebCore::XPath::Parser::lex):
        (WebCore::XPath::Parser::parseStatement):
        (WebCore::XPath::Parser::registerParseNode):
        (WebCore::XPath::Parser::unregisterParseNode):
        (WebCore::XPath::Parser::registerPredicateVector):
        (WebCore::XPath::Parser::unregisterPredicateVector):
        (WebCore::XPath::Parser::registerExpressionVector):
        (WebCore::XPath::Parser::unregisterExpressionVector):
        (WebCore::XPath::Parser::registerString):
        (WebCore::XPath::Parser::unregisterString):
        * xpath/impl/XPathParser.h: Added.
        (WebCore::XPath::Token::Token):
        (WebCore::XPath::Parser::):
        (WebCore::XPath::Parser::current):
        * xpath/impl/XPathPath.cpp: Added.
        (WebCore::XPath::Filter::Filter):
        (WebCore::XPath::Filter::~Filter):
        (WebCore::XPath::Filter::doEvaluate):
        (WebCore::XPath::LocationPath::LocationPath):
        (WebCore::XPath::LocationPath::~LocationPath):
        (WebCore::XPath::LocationPath::optimize):
        (WebCore::XPath::LocationPath::doEvaluate):
        (WebCore::XPath::Path::Path):
        (WebCore::XPath::Path::~Path):
        (WebCore::XPath::Path::doEvaluate):
        * xpath/impl/XPathPath.h: Added.
        * xpath/impl/XPathPredicate.cpp: Added.
        (WebCore::XPath::Number::Number):
        (WebCore::XPath::Number::isConstant):
        (WebCore::XPath::Number::doEvaluate):
        (WebCore::XPath::StringExpression::StringExpression):
        (WebCore::XPath::StringExpression::isConstant):
        (WebCore::XPath::StringExpression::doEvaluate):
        (WebCore::XPath::Negative::doEvaluate):
        (WebCore::XPath::NumericOp::NumericOp):
        (WebCore::XPath::NumericOp::doEvaluate):
        (WebCore::XPath::EqTestOp::EqTestOp):
        (WebCore::XPath::EqTestOp::doEvaluate):
        (WebCore::XPath::LogicalOp::LogicalOp):
        (WebCore::XPath::LogicalOp::shortCircuitOn):
        (WebCore::XPath::LogicalOp::isConstant):
        (WebCore::XPath::LogicalOp::doEvaluate):
        (WebCore::XPath::Union::doEvaluate):
        (WebCore::XPath::Predicate::Predicate):
        (WebCore::XPath::Predicate::~Predicate):
        (WebCore::XPath::Predicate::evaluate):
        (WebCore::XPath::Predicate::optimize):
        * xpath/impl/XPathPredicate.h: Added.
        (WebCore::XPath::NumericOp::):
        (WebCore::XPath::EqTestOp::):
        (WebCore::XPath::LogicalOp::):
        * xpath/impl/XPathStep.cpp: Added.
        (WebCore::XPath::Step::axisAsString):
        (WebCore::XPath::Step::Step):
        (WebCore::XPath::Step::~Step):
        (WebCore::XPath::Step::evaluate):
        (WebCore::XPath::Step::nodesInAxis):
        (WebCore::XPath::Step::nodeTestMatches):
        (WebCore::XPath::Step::optimize):
        (WebCore::XPath::Step::namespaceFromNodetest):
        (WebCore::XPath::Step::primaryNodeType):
        * xpath/impl/XPathStep.h: Added.
        (WebCore::XPath::Step::):
        * xpath/impl/XPathUtil.cpp: Added.
        (WebCore::XPath::isRootDomNode):
        (WebCore::XPath::stringValue):
        (WebCore::XPath::isValidContextNode):
        * xpath/impl/XPathUtil.h: Added.
        * xpath/impl/XPathValue.cpp: Added.
        (WebCore::XPath::Value::Value):
        (WebCore::XPath::Value::type):
        (WebCore::XPath::Value::isNodeVector):
        (WebCore::XPath::Value::isBoolean):
        (WebCore::XPath::Value::isNumber):
        (WebCore::XPath::Value::isString):
        (WebCore::XPath::Value::toNodeVector):
        (WebCore::XPath::Value::toBoolean):
        (WebCore::XPath::Value::toNumber):
        (WebCore::XPath::Value::toString):
        * xpath/impl/XPathValue.h: Added.
        (WebCore::XPath::Value::):
        * xpath/impl/XPathVariableReference.cpp: Added.
        (WebCore::XPath::VariableReference::VariableReference):
        (WebCore::XPath::VariableReference::isConstant):
        (WebCore::XPath::VariableReference::doEvaluate):
        * xpath/impl/XPathVariableReference.h: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@14234 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/xpath/impl/XPathFunctions.cpp b/WebCore/xpath/impl/XPathFunctions.cpp
new file mode 100644
index 0000000..4009a35
--- /dev/null
+++ b/WebCore/xpath/impl/XPathFunctions.cpp
@@ -0,0 +1,797 @@
+/*
+ * Copyright 2005 Frerich Raabe <raabe@kde.org>
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+
+#if XPATH_SUPPORT
+
+#include "XPathFunctions.h"
+
+#include "Logging.h"
+#include "NamedAttrMap.h"
+#include "Node.h"
+
+#include <math.h>
+
+namespace WebCore {
+namespace XPath {
+        
+#define DEFINE_FUNCTION_CREATOR(Class) \
+static Function *create##Class() { return new Class; }
+
+class Interval
+{
+public:
+    static const int Inf =-1;
+
+    Interval();
+    Interval(int value);
+    Interval(int min, int max);
+
+    bool contains(int value) const;
+
+    String asString() const;
+
+private:
+    int m_min;
+    int m_max;
+};
+
+class FunLast : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunPosition : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunCount : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunLocalName : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunNamespaceURI : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunName : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunString : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunConcat : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunStartsWith : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunContains : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunSubstringBefore : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunSubstringAfter : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunSubstring : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunStringLength : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunNormalizeSpace : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunTranslate : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunBoolean : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunNot : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunTrue : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunFalse : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunLang : public Function
+{
+public:
+    virtual bool isConstant() const;
+
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunNumber : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunSum : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunFloor : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunCeiling : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+class FunRound : public Function
+{
+private:
+    virtual Value doEvaluate() const;
+};
+
+DEFINE_FUNCTION_CREATOR(FunLast)
+DEFINE_FUNCTION_CREATOR(FunPosition)
+DEFINE_FUNCTION_CREATOR(FunCount)
+DEFINE_FUNCTION_CREATOR(FunLocalName)
+DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
+DEFINE_FUNCTION_CREATOR(FunName)
+
+DEFINE_FUNCTION_CREATOR(FunString)
+DEFINE_FUNCTION_CREATOR(FunConcat)
+DEFINE_FUNCTION_CREATOR(FunStartsWith)
+DEFINE_FUNCTION_CREATOR(FunContains)
+DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
+DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
+DEFINE_FUNCTION_CREATOR(FunSubstring)
+DEFINE_FUNCTION_CREATOR(FunStringLength)
+DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
+DEFINE_FUNCTION_CREATOR(FunTranslate)
+
+DEFINE_FUNCTION_CREATOR(FunBoolean)
+DEFINE_FUNCTION_CREATOR(FunNot)
+DEFINE_FUNCTION_CREATOR(FunTrue)
+DEFINE_FUNCTION_CREATOR(FunFalse)
+DEFINE_FUNCTION_CREATOR(FunLang)
+
+DEFINE_FUNCTION_CREATOR(FunNumber)
+DEFINE_FUNCTION_CREATOR(FunSum)
+DEFINE_FUNCTION_CREATOR(FunFloor)
+DEFINE_FUNCTION_CREATOR(FunCeiling)
+DEFINE_FUNCTION_CREATOR(FunRound)
+
+#undef DEFINE_FUNCTION_CREATOR
+
+Interval::Interval()
+    : m_min(Inf),
+    m_max(Inf)
+{
+}
+
+Interval::Interval(int value)
+    : m_min(value),
+    m_max(value)
+{
+}
+
+Interval::Interval(int min, int max)
+    : m_min(min),
+    m_max(max)
+{
+}
+
+bool Interval::contains(int value) const
+{
+    if (m_min == Inf && m_max == Inf)
+        return true;
+
+    if (m_min == Inf)
+        return value <= m_max;
+
+    if (m_max == Inf)
+        return value >= m_min;
+
+    return value >= m_min && value <= m_max;
+}
+
+String Interval::asString() const
+{
+    String s = "[";
+
+    if (m_min == Inf)
+        s += "-Infinity";
+    else
+        s += DeprecatedString::number(m_min);
+
+    s += "..";
+
+    if (m_max == Inf)
+        s += "Infinity";
+    else
+        s += DeprecatedString::number(m_max);
+
+    s += "]";
+
+    return s;
+}
+
+void Function::setArguments(const Vector<Expression*>& args)
+{
+    Vector<Expression*>::const_iterator end = args.end();
+
+    for (Vector<Expression*>::const_iterator it = args.begin(); it != end; it++)
+        addSubExpression(*it);
+}
+
+void Function::setName(const String& name)
+{
+    m_name = name;
+}
+
+Expression* Function::arg(int i)
+{
+    return subExpr(i);
+}
+
+const Expression* Function::arg(int i) const
+{
+    return subExpr(i);
+}
+
+unsigned int Function::argCount() const
+{
+    return subExprCount();
+}
+
+String Function::name() const
+{
+    return m_name;
+}
+
+Value FunLast::doEvaluate() const
+{
+    return double(Expression::evaluationContext().size);
+}
+
+bool FunLast::isConstant() const
+{
+    return false;
+}
+
+Value FunPosition::doEvaluate() const
+{
+    return double(Expression::evaluationContext().position);
+}
+
+bool FunPosition::isConstant() const
+{
+    return false;
+}
+
+bool FunLocalName::isConstant() const
+{
+    return false;
+}
+
+Value FunLocalName::doEvaluate() const
+{
+    Node* node = 0;
+    if (argCount() > 0) {
+        Value a = arg(0)->evaluate();
+        if (!a.isNodeVector() || a.toNodeVector().size() == 0)
+            return "";
+        
+        node = a.toNodeVector()[0].get();
+    }
+
+    if (!node)
+        node = evaluationContext().node.get();
+
+    return Value(node->localName());
+}
+
+bool FunNamespaceURI::isConstant() const
+{
+    return false;
+}
+
+Value FunNamespaceURI::doEvaluate() const
+{
+    Node* node = 0;
+    if (argCount() > 0) {
+        Value a = arg(0)->evaluate();
+        if (!a.isNodeVector() || a.toNodeVector().size() == 0)
+            return "";
+
+        node = a.toNodeVector()[0].get();
+    }
+
+    if (!node)
+        node = evaluationContext().node.get();
+
+    return Value(node->namespaceURI());
+}
+
+bool FunName::isConstant() const
+{
+    return false;
+}
+
+Value FunName::doEvaluate() const
+{
+    Node* node = 0;
+    if (argCount() > 0) {
+        Value a = arg(0)->evaluate();
+        if (!a.isNodeVector() || a.toNodeVector().size() == 0)
+            return "";
+
+        node = a.toNodeVector()[0].get();
+    }
+
+    if (!node)
+        node = evaluationContext().node.get();
+
+    return node->prefix() + ":" + node->localName();
+}
+
+Value FunCount::doEvaluate() const
+{
+    Value a = arg(0)->evaluate();
+    
+    if (!a.isNodeVector()) {
+        LOG(XPath, "count() expects <nodevector>");
+
+        return 0.0;
+    }
+    
+    return double(a.toNodeVector().size());
+}
+
+bool FunCount::isConstant() const
+{
+    return false;
+}
+
+Value FunString::doEvaluate() const
+{
+    if (argCount() == 0) {
+        String s = Value(Expression::evaluationContext().node).toString();
+        return s;
+    }
+    return arg(0)->evaluate().toString();
+}
+
+Value FunConcat::doEvaluate() const
+{
+    String str;
+
+    for (unsigned int i = 0; i < argCount(); ++i)
+        str += arg(i)->evaluate().toString();
+
+    return str;
+}
+
+Value FunStartsWith::doEvaluate() const
+{
+    String s1 = arg(0)->evaluate().toString();
+    String s2 = arg(1)->evaluate().toString();
+
+    if (s2.isEmpty())
+        return true;
+
+    return s1.startsWith(s2);
+}
+
+Value FunContains::doEvaluate() const
+{
+    String s1 = arg(0)->evaluate().toString();
+    String s2 = arg(1)->evaluate().toString();
+
+    if (s2.isEmpty()) 
+        return true;
+
+    return s1.contains(s2) != 0;
+}
+
+Value FunSubstringBefore::doEvaluate() const
+{
+    String s1 = arg(0)->evaluate().toString();
+    String s2 = arg(1)->evaluate().toString();
+
+    if (s2.isEmpty())
+        return "";
+
+    int i = s1.find(s2);
+
+    if (i == -1)
+        return "";
+
+    return s1.left(i);
+}
+
+Value FunSubstringAfter::doEvaluate() const
+{
+    String s1 = arg(0)->evaluate().toString();
+    String s2 = arg(1)->evaluate().toString();
+
+    if (s2.isEmpty())
+        return s2;
+
+    int i = s1.find(s2);
+    if (i == -1)
+        return "";
+
+    return Value(s1.deprecatedString().mid(i + 1));
+}
+
+Value FunSubstring::doEvaluate() const
+{
+    String s = arg(0)->evaluate().toString();
+    long pos = long(round(arg(1)->evaluate().toNumber()));
+    bool haveLength = argCount() == 3;
+    long len = -1;
+    if (haveLength)
+        len = long(round(arg(2)->evaluate().toNumber()));
+
+    if (pos > long(s.length())) 
+        return "";
+
+    if (haveLength && pos < 1) {
+        len -= 1 - pos;
+        pos = 1;
+        if (len < 1)
+            return "";
+    }
+
+    return Value(s.deprecatedString().mid(pos - 1, len));
+}
+
+Value FunStringLength::doEvaluate() const
+{
+    if (argCount() == 0) {
+        String s = Value(Expression::evaluationContext().node).toString();
+        return double(s.length());
+    }
+
+    return double(arg(0)->evaluate().toString().length());
+}
+
+Value FunNormalizeSpace::doEvaluate() const
+{
+    if (argCount() == 0) {
+        String s = Value(Expression::evaluationContext().node).toString();
+        return Value(s.deprecatedString().simplifyWhiteSpace());
+    }
+
+    String s = arg(0)->evaluate().toString();
+    return Value(s.deprecatedString().simplifyWhiteSpace());
+}
+
+Value FunTranslate::doEvaluate() const
+{
+    String s1 = arg(0)->evaluate().toString();
+    String s2 = arg(1)->evaluate().toString();
+    String s3 = arg(2)->evaluate().toString();
+    String newString;
+
+    for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
+        QChar ch = s1[i1];
+        int i2 = s2.find(ch);
+        
+        if (i2 == -1) 
+            newString += ch;
+        else if ((unsigned)i2 < s3.length())
+            newString += s3[ i2 ];
+    }
+
+    return newString;
+}
+
+Value FunBoolean::doEvaluate() const
+{
+    return arg(0)->evaluate().toBoolean();
+}
+
+Value FunNot::doEvaluate() const
+{
+    return !arg(0)->evaluate().toBoolean();
+}
+
+Value FunTrue::doEvaluate() const
+{
+    return true;
+}
+
+bool FunTrue::isConstant() const
+{
+    return true;
+}
+
+Value FunLang::doEvaluate() const
+{
+    String lang = arg(0)->evaluate().toString();
+
+    RefPtr<Node> langNode = 0;
+    Node* node = evaluationContext().node.get();
+
+    String xms("xms");
+    String xmsnsURI = node->lookupNamespaceURI(xms);
+
+    while (node) {
+        NamedAttrMap *attrs = node->attributes();
+        String l("lang");
+        langNode = attrs->getNamedItemNS(xmsnsURI, l);
+        if (langNode)
+            break;
+
+        node = node->parentNode();
+    }
+
+    if (!langNode)
+        return false;
+
+    String langNodeValue = langNode->nodeValue();
+
+    // extract 'en' out of 'en-us'
+    int index = langNodeValue.find('-');
+    if (index != -1)
+        langNodeValue = langNodeValue.left(index);
+    
+    return langNodeValue.lower() == lang.lower();
+}
+
+bool FunLang::isConstant() const
+{
+    return false;
+}
+
+Value FunFalse::doEvaluate() const
+{
+    return false;
+}
+
+bool FunFalse::isConstant() const
+{
+    return true;
+}
+
+Value FunNumber::doEvaluate() const
+{
+    return arg(0)->evaluate().toNumber();
+}
+
+Value FunSum::doEvaluate() const
+{
+    Value a = arg(0)->evaluate();
+    if (!a.isNodeVector()) {
+        LOG(XPath, "sum() expects <nodevector>");
+        return 0.0;
+    }
+
+    double sum = 0.0;
+    NodeVector nodes = a.toNodeVector();
+    
+    for (unsigned i = 0; i < nodes.size(); i++)
+        sum += Value(stringValue(nodes[i].get()).deprecatedString()).toNumber();
+    
+    return sum;
+}
+
+Value FunFloor::doEvaluate() const
+{
+    double num = arg(0)->evaluate().toNumber();
+
+    return floor(num);
+}
+
+Value FunCeiling::doEvaluate() const
+{
+    double num = arg(0)->evaluate().toNumber();
+
+    return ceil(num);
+}
+
+Value FunRound::doEvaluate() const
+{
+    return round(arg(0)->evaluate().toNumber());
+}
+
+struct FunctionLibrary::FunctionRec
+{
+    typedef Function *(*FactoryFn)();
+
+    FactoryFn factoryFn;
+    Interval args;
+};
+
+struct FunctionMapping
+{
+    const char *name;
+    FunctionLibrary::FunctionRec function;
+};
+
+FunctionLibrary& FunctionLibrary::self()
+{
+    static FunctionLibrary instance;
+    return instance;
+}
+
+FunctionLibrary::FunctionLibrary()
+{
+    static const FunctionMapping functions[] = {
+    { "last", { &createFunLast, 0 } },
+    { "last", { &createFunLast, 0 } },
+    { "position", { &createFunPosition, 0 } },
+    { "count", { &createFunCount, 1 } },
+    { "sum", { &createFunSum, 1 } },
+    { "local-name", { &createFunLocalName, Interval(0, 1) } },
+    { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
+    { "name", { &createFunName, Interval(0, 1) } },
+    { "string", { &createFunString, Interval(0, 1) } },
+    { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
+    { "starts-with", { &createFunStartsWith, 2 } },
+    { "contains", { &createFunContains, 2 } },
+    { "substring-before", { &createFunSubstringBefore, 2 } },
+    { "substring-after", { &createFunSubstringAfter, 2 } },
+    { "substring", { &createFunSubstring, Interval(2, 3) } },
+    { "string-length", { &createFunStringLength, 1 } },
+    { "normalize-space", { &createFunNormalizeSpace, 1 } },
+    { "translate", { &createFunTranslate, 3 } },
+        
+    { "boolean", { &createFunBoolean, 1 } },
+    { "not", { &createFunNot, 1 } },
+    { "true", { &createFunTrue, 0 } },
+    { "false", { &createFunFalse, 0 } },
+    { "lang", { &createFunLang, 1 } },
+        
+    { "number", { &createFunNumber, 1 } },
+    { "floor", { &createFunFloor, 1 } },
+    { "ceiling", { &createFunCeiling, 1 } },
+    { "round", { &createFunRound, 1 } }
+    };
+    const unsigned int numFunctions = sizeof(functions) / sizeof(functions[ 0 ]);
+        
+    for (unsigned i = 0; i < numFunctions; ++i)
+        m_functionDict.set(functions[i].name, functions[i].function);
+}
+
+Function *FunctionLibrary::createFunction(const char *name, const Vector<Expression*> &args) const
+{
+    if (!m_functionDict.contains(name)) {
+        LOG(XPath, "Function '%s' not supported by this implementation.", name);
+        
+        // Return a dummy function instead of 0.
+        Function *funcTrue = m_functionDict.get("true").factoryFn();
+        funcTrue->setName("true");
+        return funcTrue;
+    }
+
+    FunctionRec functionRec = m_functionDict.get(name);
+    if (!functionRec.args.contains(args.size())) {
+        LOG(XPath, "Function '%s' requires %d arguments, but %d given.", name, functionRec.args.asString().ascii(), args.size());
+        return 0;
+    }
+
+    Function *function = functionRec.factoryFn();
+    function->setArguments(args);
+    function->setName(name);
+    
+    return function;
+}
+
+}
+}
+
+#endif // XPATH_SUPPORT