Use unique_ptr instead of deleteAllValues in XPath
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Oct 2013 02:46:27 +0000 (02:46 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Oct 2013 02:46:27 +0000 (02:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=121082

Reviewed by Anders Carlsson.

* dom/Attr.h: Made the namespaceURI function public so it can be called by
code in XPath. Since the class is FINAL, calls won't do virtual dispatch.

* xml/XPathExpression.cpp:
(WebCore::XPathExpression::XPathExpression): Added. Use std::move.
(WebCore::XPathExpression::createExpression): Use the new Parser::parseStatement
and more std::move.
(WebCore::XPathExpression::~XPathExpression): Removed now-unneeded delete.
* xml/XPathExpression.h: Removed unused create function. Use std::unique_ptr.

* xml/XPathExpressionNode.cpp:
(WebCore::XPath::Expression::evaluationContext): Use NeverDestroyed instead of
DEFINE_STATIC_LOCAL.
(WebCore::XPath::Expression::setSubexpressions): Added. Used to set all the
subexpressions at once rather than adding one at a time.

* xml/XPathExpressionNode.h: Use plain unsigned instead of unsigned long.
Eliminated the ParseNode class, used only by the parser to delete objects,
which we now do with %destructor. Made more functions protected. Fixed the
capitalization of the word "subexpression". Made m_subexpressions be a Vector
of std::unique_ptr.

* xml/XPathFunctions.cpp: Marked all the classes FINAL and all their virtual
functions OVERRIDE. Reduced some of the boilerplate.
(WebCore::XPath::Function::setArguments): Passed in the name so we don't have
to store the function names in all the function objects.
(WebCore::XPath::FunId::evaluate): Use std::move instead of Value::adopt.
(WebCore::XPath::FunLocalName::evaluate): Use emptyString instead of "".
(WebCore::XPath::FunNamespaceURI::evaluate): Ditto.
(WebCore::XPath::FunName::evaluate): Ditto.
(WebCore::XPath::FunSubstringBefore::evaluate): Ditto.
(WebCore::XPath::FunSubstringAfter::evaluate): Ditto.
(WebCore::XPath::FunSubstring::evaluate): Ditto.
(WebCore::XPath::FunLang::evaluate): Use Value(false) so we can make the
constructor that takes a boolean explicit.
(WebCore::XPath::FunFalse::evaluate): Ditto.
(WebCore::XPath::populateFunctionMap): Changed idiom slightly to match other
maps we set up.
(WebCore::XPath::Function::create): Refactored createFunction into three
member functions of this name.

* xml/XPathFunctions.h: Made all the Function members private or protected
except for Function::create.

* xml/XPathGrammar.y: Changed the parser to use a reference instead of
a pointer, and to pass the reference through to yylex as well. Break up
the union into pieces and add %destructor as needed to make sure everything
gets deallocated if parsing fails. Added a new top level rule "Top" so that
we would not try to set the parse result multiple times during parsing.
Call setParseResult instead of setting m_topExpr directly. Use std::unique_ptr
to adopt pointers from the union. Removed all the register/unregister calls
that used to be used to manage storage. Also changed the four different node
types to be separate tokens instead of using string matching at this level
for them.

* xml/XPathNodeSet.cpp:
(WebCore::XPath::NodeSet::sort): Removed const_cast since m_isSorted and
m_nodes are now both marked mutable. Also set m_isSorted after sorting; this
was an oversight that hurt performance before.
(WebCore::XPath::NodeSet::traversalSort): Ditto.
(WebCore::XPath::NodeSet::firstNode): Use nullptr.
(WebCore::XPath::NodeSet::anyNode): Ditto.

* xml/XPathNodeSet.h: Removed unneeded extra includes. Removed the
WTF_MAKE_FAST_ALLOCATED for NodeSet since we never allocate these on the heap.
Added a constructor that takes a single node. Deleted the swap function, since
we now move instead of swap. Deleted the append function that takes a raw Node*,
since calling the PassRefPtr<Node> overload does the same thing. Removed the
unused reverse function. Marked both m_isSorted and m_nodes mutable so the
sort function can be const.

* xml/XPathParser.cpp: Moved the Token struct in here instead of the header.
(WebCore::XPath::populateAxisNamesMap):Renamed to match our normal naming scheme,
and changed to use add instead of set, use WTF_ARRAY_LENGTH, and not use a typedef.
(WebCore::XPath::parseAxisName): Related style changes, including renaming to
better reflect the way this works with a boolean.
(WebCore::XPath::Parser::nextTokenInternal): Updated to call parseAxisName,
and to produce four separate tokens for the four node type functions.
(WebCore::XPath::Parser::nextToken): Renamed local variable.
(WebCore::XPath::Parser::Parser): Made this a real constructor that takes arguments
and initializes all the fields. Deleted the unneeded reset function.
(WebCore::XPath::Parser::lex): Changed to take an argument of an appropriate type
instead of casting from void*. Also changed the string code to leak a StringImpl,
which is now what the grammar code expects.
(WebCore::XPath::Parser::expandQualifiedName): Renamed from expandQName. Changed
to set m_sawNamespaceError instead of relying on code in the grammar to do it.
(WebCore::XPath::Parser::parseStatement): Removed most of the code in this function.
Changed to a much simpler model. Also made this a static member function so it
takes care of creating the parser itself and does not need to call reset. Also
changed return value to be a std::unique_ptr to make ownership more clear.

* xml/XPathParser.h: Added a declaration of YYSTYPE. Removed unneeded forward
declarations and moved Token into the cpp file. Deleted most public functions,
leaving only parseStatement, the entry point, and the three functions needed by
the grammar, lex, expandQualifiedName, and setParseResult.

* xml/XPathPath.cpp:
(WebCore::XPath::Filter::Filter): Move in the arguments instead of copying them.
(WebCore::XPath::Filter::evaluate): Updated for name and type changes.
(WebCore::XPath::LocationPath::LocationPath): Ditto.
(WebCore::XPath::LocationPath::evaluate): Ditto. Also use std::move instead of
Value::adopt and instead of swap.
(WebCore::XPath::LocationPath::appendStep): Changed to take ownership of a
unique_ptr.
(WebCore::XPath::LocationPath::prependStep): Ditto. Renamed from insertFirstStep.
(WebCore::XPath::Path::Path): Move in the arguments.

* xml/XPathPath.h: Removed unneeded includes. Changed arugument types to use
std::unique_ptr to pass ownership in. Added override to all virtual functions.
Changed data members to use std::unique_ptr.

* xml/XPathPredicate.cpp:
(WebCore::XPath::StringExpression::StringExpression): Use move.
(WebCore::XPath::Negative::Negative): Added.
(WebCore::XPath::Negative::evaluate): Updated for name changes.
(WebCore::XPath::NumericOp::NumericOp): Use move.
(WebCore::XPath::NumericOp::evaluate): Tweak formatting.
(WebCore::XPath::EqTestOp::EqTestOp): Use move.
(WebCore::XPath::EqTestOp::evaluate): Updated for name changes.
(WebCore::XPath::LogicalOp::LogicalOp): Use move.
(WebCore::XPath::LogicalOp::shortCircuitOn): Made shorter.
(WebCore::XPath::LogicalOp::evaluate): Updated for name changes.
(WebCore::XPath::Union::Union): Added.
(WebCore::XPath::Union::evaluate): Updated for name changes.
(WebCore::XPath::evaluatePredicate): Updated for name changes, to use
ASCIILiteral, and to be a free function that takes an expression.
(WebCore::XPath::predicateIsContextPositionSensitive): Added.
Replaces the Predicate::isContextPositionSensitive function.

* xml/XPathPredicate.h: Made all the classes FINAL and added a lot of OVERRIDE.
Added a constructor for Negative and Union. Got rid of the Predicate class and
instead provided two functions that operate on an Expression.

* xml/XPathStep.cpp:
(WebCore::XPath::Step::Step): Use move instea dof copying.
(WebCore::XPath::Step::~Step): Removed calls to deleteAllValues.
(WebCore::XPath::Step::optimize): Use move instead of swap and copy. Also
operate directly on the data members of the node test instead of using functions
that just return references to those data members.
(WebCore::XPath::optimizeStepPair): Use references instead of pointers, move
instead of swap, and early return instead of nested if statements.
(WebCore::XPath::Step::predicatesAreContextListInsensitive): Use references.
(WebCore::XPath::Step::evaluate): Use references instead of pointers and move
instead of swap.
(WebCore::XPath::nodeMatchesBasicTest): Use references instead of pointers and
more specific types when possible.
(WebCore::XPath::nodeMatches): Ditto.
(WebCore::XPath::Step::nodesInAxis): Use references instead of pointers. Added
braces to match style. Use words instead of letters for local variable names.

* xml/XPathStep.h: Make almost everything in NodeTest private since callers
just set these up and Step is what actually uses them. Changed the predicate
vectors to be vectors of Predicate instead of Predicate*, since a Predicate
is just a wrapper around a single std::unique_ptr<Expression>. Changed to use
move instead of copy when making a Step and to use references instead of pointers.

* xml/XPathValue.cpp: Use std::numeric_limits explicitly instead of using using.
Got rid of Value::adopt.
(WebCore::XPath::Value::toNodeSet): Use NeverDestroyed instead of DEFINE_STATE_LOCAL.
Updated for name changes.
(WebCore::XPath::Value::modifiableNodeSet): Ditto.
(WebCore::XPath::Value::toBoolean): Ditto.
(WebCore::XPath::Value::toNumber): Ditto.
(WebCore::XPath::Value::toString): Ditto. Use ASCIILiteral.

* xml/XPathValue.h: Moved ValueData class inside the Value class and renamed
it Value::Data. Removed fancy trick that avoids turning pointers into bool, and
just take the risk. Made many, but not all, of the Value constructors explicit
since we normally are explicit at call sites. Removed unneeded unsigned long
overload of the constructor. Changed the NodeSet version of the constructor to
use std::move and use that instead of AdoptTag.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@157205 268f45cc-cd09-0410-ab3c-d52691b4dbfc

22 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/Attr.h
Source/WebCore/xml/XPathExpression.cpp
Source/WebCore/xml/XPathExpression.h
Source/WebCore/xml/XPathExpressionNode.cpp
Source/WebCore/xml/XPathExpressionNode.h
Source/WebCore/xml/XPathFunctions.cpp
Source/WebCore/xml/XPathFunctions.h
Source/WebCore/xml/XPathGrammar.y
Source/WebCore/xml/XPathNodeSet.cpp
Source/WebCore/xml/XPathNodeSet.h
Source/WebCore/xml/XPathParser.cpp
Source/WebCore/xml/XPathParser.h
Source/WebCore/xml/XPathPath.cpp
Source/WebCore/xml/XPathPath.h
Source/WebCore/xml/XPathPredicate.cpp
Source/WebCore/xml/XPathPredicate.h
Source/WebCore/xml/XPathStep.cpp
Source/WebCore/xml/XPathStep.h
Source/WebCore/xml/XPathUtil.cpp
Source/WebCore/xml/XPathValue.cpp
Source/WebCore/xml/XPathValue.h

index af03a53..9f77a01 100644 (file)
@@ -1,3 +1,182 @@
+2013-10-07  Darin Adler  <darin@apple.com>
+
+        Use unique_ptr instead of deleteAllValues in XPath
+        https://bugs.webkit.org/show_bug.cgi?id=121082
+
+        Reviewed by Anders Carlsson.
+
+        * dom/Attr.h: Made the namespaceURI function public so it can be called by
+        code in XPath. Since the class is FINAL, calls won't do virtual dispatch.
+
+        * xml/XPathExpression.cpp:
+        (WebCore::XPathExpression::XPathExpression): Added. Use std::move.
+        (WebCore::XPathExpression::createExpression): Use the new Parser::parseStatement
+        and more std::move.
+        (WebCore::XPathExpression::~XPathExpression): Removed now-unneeded delete.
+        * xml/XPathExpression.h: Removed unused create function. Use std::unique_ptr.
+
+        * xml/XPathExpressionNode.cpp:
+        (WebCore::XPath::Expression::evaluationContext): Use NeverDestroyed instead of
+        DEFINE_STATIC_LOCAL.
+        (WebCore::XPath::Expression::setSubexpressions): Added. Used to set all the
+        subexpressions at once rather than adding one at a time.
+
+        * xml/XPathExpressionNode.h: Use plain unsigned instead of unsigned long.
+        Eliminated the ParseNode class, used only by the parser to delete objects,
+        which we now do with %destructor. Made more functions protected. Fixed the
+        capitalization of the word "subexpression". Made m_subexpressions be a Vector
+        of std::unique_ptr.
+
+        * xml/XPathFunctions.cpp: Marked all the classes FINAL and all their virtual
+        functions OVERRIDE. Reduced some of the boilerplate.
+        (WebCore::XPath::Function::setArguments): Passed in the name so we don't have
+        to store the function names in all the function objects.
+        (WebCore::XPath::FunId::evaluate): Use std::move instead of Value::adopt.
+        (WebCore::XPath::FunLocalName::evaluate): Use emptyString instead of "".
+        (WebCore::XPath::FunNamespaceURI::evaluate): Ditto.
+        (WebCore::XPath::FunName::evaluate): Ditto.
+        (WebCore::XPath::FunSubstringBefore::evaluate): Ditto.
+        (WebCore::XPath::FunSubstringAfter::evaluate): Ditto.
+        (WebCore::XPath::FunSubstring::evaluate): Ditto.
+        (WebCore::XPath::FunLang::evaluate): Use Value(false) so we can make the
+        constructor that takes a boolean explicit.
+        (WebCore::XPath::FunFalse::evaluate): Ditto.
+        (WebCore::XPath::populateFunctionMap): Changed idiom slightly to match other
+        maps we set up.
+        (WebCore::XPath::Function::create): Refactored createFunction into three
+        member functions of this name.
+
+        * xml/XPathFunctions.h: Made all the Function members private or protected
+        except for Function::create.
+
+        * xml/XPathGrammar.y: Changed the parser to use a reference instead of
+        a pointer, and to pass the reference through to yylex as well. Break up
+        the union into pieces and add %destructor as needed to make sure everything
+        gets deallocated if parsing fails. Added a new top level rule "Top" so that
+        we would not try to set the parse result multiple times during parsing.
+        Call setParseResult instead of setting m_topExpr directly. Use std::unique_ptr
+        to adopt pointers from the union. Removed all the register/unregister calls
+        that used to be used to manage storage. Also changed the four different node
+        types to be separate tokens instead of using string matching at this level
+        for them.
+
+        * xml/XPathNodeSet.cpp:
+        (WebCore::XPath::NodeSet::sort): Removed const_cast since m_isSorted and
+        m_nodes are now both marked mutable. Also set m_isSorted after sorting; this
+        was an oversight that hurt performance before.
+        (WebCore::XPath::NodeSet::traversalSort): Ditto.
+        (WebCore::XPath::NodeSet::firstNode): Use nullptr.
+        (WebCore::XPath::NodeSet::anyNode): Ditto.
+
+        * xml/XPathNodeSet.h: Removed unneeded extra includes. Removed the
+        WTF_MAKE_FAST_ALLOCATED for NodeSet since we never allocate these on the heap.
+        Added a constructor that takes a single node. Deleted the swap function, since
+        we now move instead of swap. Deleted the append function that takes a raw Node*,
+        since calling the PassRefPtr<Node> overload does the same thing. Removed the
+        unused reverse function. Marked both m_isSorted and m_nodes mutable so the
+        sort function can be const.
+
+        * xml/XPathParser.cpp: Moved the Token struct in here instead of the header.
+        (WebCore::XPath::populateAxisNamesMap):Renamed to match our normal naming scheme,
+        and changed to use add instead of set, use WTF_ARRAY_LENGTH, and not use a typedef.
+        (WebCore::XPath::parseAxisName): Related style changes, including renaming to
+        better reflect the way this works with a boolean.
+        (WebCore::XPath::Parser::nextTokenInternal): Updated to call parseAxisName,
+        and to produce four separate tokens for the four node type functions.
+        (WebCore::XPath::Parser::nextToken): Renamed local variable.
+        (WebCore::XPath::Parser::Parser): Made this a real constructor that takes arguments
+        and initializes all the fields. Deleted the unneeded reset function.
+        (WebCore::XPath::Parser::lex): Changed to take an argument of an appropriate type
+        instead of casting from void*. Also changed the string code to leak a StringImpl,
+        which is now what the grammar code expects.
+        (WebCore::XPath::Parser::expandQualifiedName): Renamed from expandQName. Changed
+        to set m_sawNamespaceError instead of relying on code in the grammar to do it.
+        (WebCore::XPath::Parser::parseStatement): Removed most of the code in this function.
+        Changed to a much simpler model. Also made this a static member function so it
+        takes care of creating the parser itself and does not need to call reset. Also
+        changed return value to be a std::unique_ptr to make ownership more clear.
+
+        * xml/XPathParser.h: Added a declaration of YYSTYPE. Removed unneeded forward
+        declarations and moved Token into the cpp file. Deleted most public functions,
+        leaving only parseStatement, the entry point, and the three functions needed by
+        the grammar, lex, expandQualifiedName, and setParseResult.
+
+        * xml/XPathPath.cpp:
+        (WebCore::XPath::Filter::Filter): Move in the arguments instead of copying them.
+        (WebCore::XPath::Filter::evaluate): Updated for name and type changes.
+        (WebCore::XPath::LocationPath::LocationPath): Ditto.
+        (WebCore::XPath::LocationPath::evaluate): Ditto. Also use std::move instead of
+        Value::adopt and instead of swap.
+        (WebCore::XPath::LocationPath::appendStep): Changed to take ownership of a
+        unique_ptr.
+        (WebCore::XPath::LocationPath::prependStep): Ditto. Renamed from insertFirstStep.
+        (WebCore::XPath::Path::Path): Move in the arguments.
+
+        * xml/XPathPath.h: Removed unneeded includes. Changed arugument types to use
+        std::unique_ptr to pass ownership in. Added override to all virtual functions.
+        Changed data members to use std::unique_ptr.
+
+        * xml/XPathPredicate.cpp:
+        (WebCore::XPath::StringExpression::StringExpression): Use move.
+        (WebCore::XPath::Negative::Negative): Added.
+        (WebCore::XPath::Negative::evaluate): Updated for name changes.
+        (WebCore::XPath::NumericOp::NumericOp): Use move.
+        (WebCore::XPath::NumericOp::evaluate): Tweak formatting.
+        (WebCore::XPath::EqTestOp::EqTestOp): Use move.
+        (WebCore::XPath::EqTestOp::evaluate): Updated for name changes.
+        (WebCore::XPath::LogicalOp::LogicalOp): Use move.
+        (WebCore::XPath::LogicalOp::shortCircuitOn): Made shorter.
+        (WebCore::XPath::LogicalOp::evaluate): Updated for name changes.
+        (WebCore::XPath::Union::Union): Added.
+        (WebCore::XPath::Union::evaluate): Updated for name changes.
+        (WebCore::XPath::evaluatePredicate): Updated for name changes, to use
+        ASCIILiteral, and to be a free function that takes an expression.
+        (WebCore::XPath::predicateIsContextPositionSensitive): Added.
+        Replaces the Predicate::isContextPositionSensitive function.
+
+        * xml/XPathPredicate.h: Made all the classes FINAL and added a lot of OVERRIDE.
+        Added a constructor for Negative and Union. Got rid of the Predicate class and
+        instead provided two functions that operate on an Expression.
+
+        * xml/XPathStep.cpp:
+        (WebCore::XPath::Step::Step): Use move instea dof copying.
+        (WebCore::XPath::Step::~Step): Removed calls to deleteAllValues.
+        (WebCore::XPath::Step::optimize): Use move instead of swap and copy. Also
+        operate directly on the data members of the node test instead of using functions
+        that just return references to those data members.
+        (WebCore::XPath::optimizeStepPair): Use references instead of pointers, move
+        instead of swap, and early return instead of nested if statements.
+        (WebCore::XPath::Step::predicatesAreContextListInsensitive): Use references.
+        (WebCore::XPath::Step::evaluate): Use references instead of pointers and move
+        instead of swap.
+        (WebCore::XPath::nodeMatchesBasicTest): Use references instead of pointers and
+        more specific types when possible.
+        (WebCore::XPath::nodeMatches): Ditto.
+        (WebCore::XPath::Step::nodesInAxis): Use references instead of pointers. Added
+        braces to match style. Use words instead of letters for local variable names.
+
+        * xml/XPathStep.h: Make almost everything in NodeTest private since callers
+        just set these up and Step is what actually uses them. Changed the predicate
+        vectors to be vectors of Predicate instead of Predicate*, since a Predicate
+        is just a wrapper around a single std::unique_ptr<Expression>. Changed to use
+        move instead of copy when making a Step and to use references instead of pointers.
+
+        * xml/XPathValue.cpp: Use std::numeric_limits explicitly instead of using using.
+        Got rid of Value::adopt.
+        (WebCore::XPath::Value::toNodeSet): Use NeverDestroyed instead of DEFINE_STATE_LOCAL.
+        Updated for name changes.
+        (WebCore::XPath::Value::modifiableNodeSet): Ditto.
+        (WebCore::XPath::Value::toBoolean): Ditto.
+        (WebCore::XPath::Value::toNumber): Ditto.
+        (WebCore::XPath::Value::toString): Ditto. Use ASCIILiteral.
+
+        * xml/XPathValue.h: Moved ValueData class inside the Value class and renamed
+        it Value::Data. Removed fancy trick that avoids turning pointers into bool, and
+        just take the risk. Made many, but not all, of the Value constructors explicit
+        since we normally are explicit at call sites. Removed unneeded unsigned long
+        overload of the constructor. Changed the NodeSet version of the constructor to
+        use std::move and use that instead of AdoptTag.
+
 2013-10-09  Ryosuke Niwa  <rniwa@webkit.org>
 
         Build fix. Add back the missing call to EventRetargeter::adjustForTouchEvent.
index 0584a5e..269d0b0 100644 (file)
@@ -64,6 +64,8 @@ public:
     void attachToElement(Element*);
     void detachFromElementWithValue(const AtomicString&);
 
+    virtual const AtomicString& namespaceURI() const OVERRIDE { return m_name.namespaceURI(); }
+
 private:
     Attr(Element*, const QualifiedName&);
     Attr(Document&, const QualifiedName&, const AtomicString& value);
@@ -74,7 +76,6 @@ private:
     virtual NodeType nodeType() const OVERRIDE { return ATTRIBUTE_NODE; }
 
     virtual const AtomicString& localName() const OVERRIDE { return m_name.localName(); }
-    virtual const AtomicString& namespaceURI() const OVERRIDE { return m_name.namespaceURI(); }
     virtual const AtomicString& prefix() const OVERRIDE { return m_name.prefix(); }
 
     virtual void setPrefix(const AtomicString&, ExceptionCode&) OVERRIDE;
index 33644c2..e456e19 100644 (file)
@@ -41,21 +41,22 @@ namespace WebCore {
 
 using namespace XPath;
     
-PassRefPtr<XPathExpression> XPathExpression::createExpression(const String& expression, XPathNSResolver* resolver, ExceptionCode& ec)
+inline XPathExpression::XPathExpression(std::unique_ptr<XPath::Expression> expression)
+    : m_topExpression(std::move(expression))
 {
-    RefPtr<XPathExpression> expr = XPathExpression::create();
-    Parser parser;
+}
 
-    expr->m_topExpression = parser.parseStatement(expression, resolver, ec);
-    if (!expr->m_topExpression)
-        return 0;
+PassRefPtr<XPathExpression> XPathExpression::createExpression(const String& expression, XPathNSResolver* resolver, ExceptionCode& ec)
+{
+    auto parsedExpression = Parser::parseStatement(expression, resolver, ec);
+    if (!parsedExpression)
+        return nullptr;
 
-    return expr.release();
+    return adoptRef(new XPathExpression(std::move(parsedExpression)));
 }
 
 XPathExpression::~XPathExpression()
 {
-    delete m_topExpression;
 }
 
 PassRefPtr<XPathResult> XPathExpression::evaluate(Node* contextNode, unsigned short type, XPathResult*, ExceptionCode& ec)
@@ -71,20 +72,20 @@ PassRefPtr<XPathResult> XPathExpression::evaluate(Node* contextNode, unsigned sh
     evaluationContext.position = 1;
     evaluationContext.hadTypeConversionError = false;
     RefPtr<XPathResult> result = XPathResult::create(&contextNode->document(), m_topExpression->evaluate());
-    evaluationContext.node = 0; // Do not hold a reference to the context node, as this may prevent the whole document from being destroyed in time.
+    evaluationContext.node = nullptr; // Do not hold a reference to the context node, as this may prevent the whole document from being destroyed in time.
 
     if (evaluationContext.hadTypeConversionError) {
         // It is not specified what to do if type conversion fails while evaluating an expression, and INVALID_EXPRESSION_ERR is not exactly right
         // when the failure happens in an otherwise valid expression because of a variable. But XPathEvaluator does not support variables, so it's close enough.
         ec = XPathException::INVALID_EXPRESSION_ERR;
-        return 0;
+        return nullptr;
     }
 
     if (type != XPathResult::ANY_TYPE) {
         ec = 0;
         result->convertTo(type, ec);
         if (ec)
-            return 0;
+            return nullptr;
     }
 
     return result;
index 3124939..8fd2a3e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,7 +29,6 @@
 
 #include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
-#include <wtf/PassRefPtr.h>
 
 namespace WebCore {
 
@@ -45,16 +44,15 @@ namespace WebCore {
 
     class XPathExpression : public RefCounted<XPathExpression> {
     public:
-        static PassRefPtr<XPathExpression> create() { return adoptRef(new XPathExpression); }
+        static PassRefPtr<XPathExpression> createExpression(const String& expression, XPathNSResolver*, ExceptionCode&);
         ~XPathExpression();
         
-        static PassRefPtr<XPathExpression> createExpression(const String& expression, XPathNSResolver*, ExceptionCode&);
         PassRefPtr<XPathResult> evaluate(Node* contextNode, unsigned short type, XPathResult*, ExceptionCode&);
             
     private:
-        XPathExpression() { }
+        explicit XPathExpression(std::unique_ptr<XPath::Expression>);
 
-        XPath::Expression* m_topExpression;
+        std::unique_ptr<XPath::Expression> m_topExpression;
     };
 
 }
index e37ccda..476481f 100644 (file)
@@ -28,6 +28,7 @@
 #include "XPathExpressionNode.h"
 
 #include "Node.h"
+#include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
 
 namespace WebCore {
@@ -35,8 +36,8 @@ namespace XPath {
 
 EvaluationContext& Expression::evaluationContext()
 {
-    DEFINE_STATIC_LOCAL(EvaluationContext, evaluationContext, ());
-    return evaluationContext;
+    static NeverDestroyed<EvaluationContext> context;
+    return context;
 }
 
 Expression::Expression()
@@ -46,9 +47,15 @@ Expression::Expression()
 {
 }
 
-Expression::~Expression()
+void Expression::setSubexpressions(Vector<std::unique_ptr<Expression>> subexpressions)
 {
-    deleteAllValues(m_subExpressions);
+    ASSERT(m_subexpressions.isEmpty());
+    m_subexpressions = std::move(subexpressions);
+    for (unsigned i = 0; i < m_subexpressions.size(); ++i) {
+        m_isContextNodeSensitive |= m_subexpressions[i]->m_isContextNodeSensitive;
+        m_isContextPositionSensitive |= m_subexpressions[i]->m_isContextPositionSensitive;
+        m_isContextSizeSensitive |= m_subexpressions[i]->m_isContextSizeSensitive;
+    }
 }
 
 } // namespace XPath
index 1ece4b3..cf26113 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006, 2009, 2013 Apple Inc.
+ * Copyright (C) 2006, 2009, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #ifndef XPathExpressionNode_h
 #define XPathExpressionNode_h
 
-#include "Node.h"
 #include "XPathValue.h"
-#include <wtf/HashMap.h>
-#include <wtf/Vector.h>
-#include <wtf/text/StringHash.h>
 
 namespace WebCore {
 namespace XPath {
 
 struct EvaluationContext {
-    WTF_MAKE_FAST_ALLOCATED;
-public:
     RefPtr<Node> node;
-    unsigned long size;
-    unsigned long position;
+    unsigned size;
+    unsigned position;
     HashMap<String, String> variableBindings;
 
     bool hadTypeConversionError;
 };
 
-class ParseNode {
-public:
-    virtual ~ParseNode() { }
-};
-
-class Expression : public ParseNode {
+class Expression {
     WTF_MAKE_NONCOPYABLE(Expression); WTF_MAKE_FAST_ALLOCATED;
 public:
     static EvaluationContext& evaluationContext();
 
-    virtual ~Expression();
+    virtual ~Expression() { }
 
-    void addSubExpression(Expression* expr)
-    {
-        m_subExpressions.append(expr);
-        m_isContextNodeSensitive |= expr->m_isContextNodeSensitive;
-        m_isContextPositionSensitive |= expr->m_isContextPositionSensitive;
-        m_isContextSizeSensitive |= expr->m_isContextSizeSensitive;
-    }
+    virtual Value evaluate() const = 0;
+    virtual Value::Type resultType() const = 0;
 
     bool isContextNodeSensitive() const { return m_isContextNodeSensitive; }
-    void setIsContextNodeSensitive(bool value) { m_isContextNodeSensitive = value; }
-
     bool isContextPositionSensitive() const { return m_isContextPositionSensitive; }
-    void setIsContextPositionSensitive(bool value) { m_isContextPositionSensitive = value; }
-
     bool isContextSizeSensitive() const { return m_isContextSizeSensitive; }
-    void setIsContextSizeSensitive(bool value) { m_isContextSizeSensitive = value; }
-
-    virtual Value evaluate() const = 0;
-    virtual Value::Type resultType() const = 0;
 
 protected:
     Expression();
 
-    unsigned subExpressionCount() const { return m_subExpressions.size(); }
-    const Expression& subExpression(unsigned i) const { return *m_subExpressions[i]; }
+    unsigned subexpressionCount() const { return m_subexpressions.size(); }
+    const Expression& subexpression(unsigned i) const { return *m_subexpressions[i]; }
+
+    void addSubexpression(std::unique_ptr<Expression> expression)
+    {
+        m_isContextNodeSensitive |= expression->m_isContextNodeSensitive;
+        m_isContextPositionSensitive |= expression->m_isContextPositionSensitive;
+        m_isContextSizeSensitive |= expression->m_isContextSizeSensitive;
+        m_subexpressions.append(std::move(expression));
+    }
+
+    void setSubexpressions(Vector<std::unique_ptr<Expression>>);
+
+    void setIsContextNodeSensitive(bool value) { m_isContextNodeSensitive = value; }
+    void setIsContextPositionSensitive(bool value) { m_isContextPositionSensitive = value; }
+    void setIsContextSizeSensitive(bool value) { m_isContextSizeSensitive = value; }
 
 private:
-    Vector<Expression*> m_subExpressions;
+    Vector<std::unique_ptr<Expression>> m_subexpressions;
 
     // Evaluation details that can be used for optimization.
     bool m_isContextNodeSensitive;
index 2d24e1a..bc59325 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006, 2009 Apple Inc.
+ * Copyright (C) 2006, 2009, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include "XPathUtil.h"
 #include "XPathValue.h"
 #include <wtf/MathExtras.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/text/StringBuilder.h>
 
 namespace WebCore {
@@ -45,8 +46,7 @@ static inline bool isWhitespace(UChar c)
     return c == ' ' || c == '\n' || c == '\r' || c == '\t';
 }
 
-
-#define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
+#define DEFINE_FUNCTION_CREATOR(Suffix) static std::unique_ptr<Function> createFunction##Suffix() { return std::make_unique<Fun##Suffix>(); }
 
 class Interval {
 public:
@@ -63,201 +63,193 @@ private:
     int m_max;
 };
 
-struct FunctionRec {
-    typedef Function *(*FactoryFn)();
-    FactoryFn factoryFn;
-    Interval args;
-};
-
-static HashMap<String, FunctionRec>* functionMap;
-
-class FunLast : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunLast FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 public:
     FunLast() { setIsContextSizeSensitive(true); }
 };
 
-class FunPosition : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunPosition FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 public:
     FunPosition() { setIsContextPositionSensitive(true); }
 };
 
-class FunCount : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunCount FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 };
 
-class FunId : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NodeSetValue; }
+class FunId FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
 };
 
-class FunLocalName : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunLocalName FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 public:
     FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node. 
 };
 
-class FunNamespaceURI : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunNamespaceURI FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 public:
     FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node. 
 };
 
-class FunName : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunName FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 public:
     FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node. 
 };
 
-class FunString : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunString FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 public:
     FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node. 
 };
 
-class FunConcat : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunConcat FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 };
 
-class FunStartsWith : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+class FunStartsWith FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 };
 
-class FunContains : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+class FunContains FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 };
 
-class FunSubstringBefore : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunSubstringBefore FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 };
 
-class FunSubstringAfter : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunSubstringAfter FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 };
 
-class FunSubstring : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunSubstring FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 };
 
-class FunStringLength : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunStringLength FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 public:
     FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node. 
 };
 
-class FunNormalizeSpace : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunNormalizeSpace FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 public:
     FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node. 
 };
 
-class FunTranslate : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::StringValue; }
+class FunTranslate FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 };
 
-class FunBoolean : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+class FunBoolean FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 };
 
 class FunNot : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 };
 
-class FunTrue : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+class FunTrue FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 };
 
-class FunFalse : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+class FunFalse FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 };
 
-class FunLang : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::BooleanValue; }
+class FunLang FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
 public:
     FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node. 
 };
 
-class FunNumber : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunNumber FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 public:
     FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node. 
 };
 
-class FunSum : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunSum FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 };
 
-class FunFloor : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunFloor FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 };
 
-class FunCeiling : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunCeiling FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 };
 
-class FunRound : public Function {
-    virtual Value evaluate() const;
-    virtual Value::Type resultType() const { return Value::NumberValue; }
+class FunRound FINAL : public Function {
+    virtual Value evaluate() const OVERRIDE;
+    virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 public:
     static double round(double);
 };
 
-DEFINE_FUNCTION_CREATOR(FunLast)
-DEFINE_FUNCTION_CREATOR(FunPosition)
-DEFINE_FUNCTION_CREATOR(FunCount)
-DEFINE_FUNCTION_CREATOR(FunId)
-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)
+DEFINE_FUNCTION_CREATOR(Last)
+DEFINE_FUNCTION_CREATOR(Position)
+DEFINE_FUNCTION_CREATOR(Count)
+DEFINE_FUNCTION_CREATOR(Id)
+DEFINE_FUNCTION_CREATOR(LocalName)
+DEFINE_FUNCTION_CREATOR(NamespaceURI)
+DEFINE_FUNCTION_CREATOR(Name)
+
+DEFINE_FUNCTION_CREATOR(String)
+DEFINE_FUNCTION_CREATOR(Concat)
+DEFINE_FUNCTION_CREATOR(StartsWith)
+DEFINE_FUNCTION_CREATOR(Contains)
+DEFINE_FUNCTION_CREATOR(SubstringBefore)
+DEFINE_FUNCTION_CREATOR(SubstringAfter)
+DEFINE_FUNCTION_CREATOR(Substring)
+DEFINE_FUNCTION_CREATOR(StringLength)
+DEFINE_FUNCTION_CREATOR(NormalizeSpace)
+DEFINE_FUNCTION_CREATOR(Translate)
+
+DEFINE_FUNCTION_CREATOR(Boolean)
+DEFINE_FUNCTION_CREATOR(Not)
+DEFINE_FUNCTION_CREATOR(True)
+DEFINE_FUNCTION_CREATOR(False)
+DEFINE_FUNCTION_CREATOR(Lang)
+
+DEFINE_FUNCTION_CREATOR(Number)
+DEFINE_FUNCTION_CREATOR(Sum)
+DEFINE_FUNCTION_CREATOR(Floor)
+DEFINE_FUNCTION_CREATOR(Ceiling)
+DEFINE_FUNCTION_CREATOR(Round)
 
 #undef DEFINE_FUNCTION_CREATOR
 
@@ -290,17 +282,17 @@ inline bool Interval::contains(int value) const
     return value >= m_min && value <= m_max;
 }
 
-void Function::setArguments(const Vector<Expression*>& args)
+void Function::setArguments(const String& name, Vector<std::unique_ptr<Expression>> arguments)
 {
-    ASSERT(!subExpressionCount());
+    ASSERT(!subexpressionCount());
 
-    // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive.
-    if (m_name != "lang" && !args.isEmpty())
+    // Functions that use the context node as an implicit argument are context node sensitive when they
+    // have no arguments, but when explicit arguments are added, they are no longer context node sensitive.
+    // As of this writing, the only exception to this is the "lang" function.
+    if (name != "lang" && !arguments.isEmpty())
         setIsContextNodeSensitive(false);
 
-    Vector<Expression*>::const_iterator end = args.end();
-    for (Vector<Expression*>::const_iterator it = args.begin(); it != end; ++it)
-        addSubExpression(*it);
+    setSubexpressions(std::move(arguments));
 }
 
 Value FunLast::evaluate() const
@@ -358,7 +350,7 @@ Value FunId::evaluate() const
     
     result.markSorted(false);
     
-    return Value(result, Value::adopt);
+    return Value(std::move(result));
 }
 
 static inline String expandedNameLocalPart(Node* node)
@@ -381,10 +373,10 @@ Value FunLocalName::evaluate() const
     if (argumentCount() > 0) {
         Value a = argument(0).evaluate();
         if (!a.isNodeSet())
-            return "";
+            return emptyString();
 
         Node* node = a.toNodeSet().firstNode();
-        return node ? expandedNameLocalPart(node) : "";
+        return node ? expandedNameLocalPart(node) : emptyString();
     }
 
     return expandedNameLocalPart(evaluationContext().node.get());
@@ -395,10 +387,10 @@ Value FunNamespaceURI::evaluate() const
     if (argumentCount() > 0) {
         Value a = argument(0).evaluate();
         if (!a.isNodeSet())
-            return "";
+            return emptyString();
 
         Node* node = a.toNodeSet().firstNode();
-        return node ? node->namespaceURI().string() : "";
+        return node ? node->namespaceURI().string() : emptyString();
     }
 
     return evaluationContext().node->namespaceURI().string();
@@ -409,10 +401,10 @@ Value FunName::evaluate() const
     if (argumentCount() > 0) {
         Value a = argument(0).evaluate();
         if (!a.isNodeSet())
-            return "";
+            return emptyString();
 
         Node* node = a.toNodeSet().firstNode();
-        return node ? expandedName(node) : "";
+        return node ? expandedName(node) : emptyString();
     }
 
     return expandedName(evaluationContext().node.get());
@@ -473,12 +465,12 @@ Value FunSubstringBefore::evaluate() const
     String s2 = argument(1).evaluate().toString();
 
     if (s2.isEmpty())
-        return "";
+        return emptyString();
 
     size_t i = s1.find(s2);
 
     if (i == notFound)
-        return "";
+        return emptyString();
 
     return s1.left(i);
 }
@@ -490,7 +482,7 @@ Value FunSubstringAfter::evaluate() const
 
     size_t i = s1.find(s2);
     if (i == notFound)
-        return "";
+        return emptyString();
 
     return s1.substring(i + s2.length());
 }
@@ -500,25 +492,25 @@ Value FunSubstring::evaluate() const
     String s = argument(0).evaluate().toString();
     double doublePos = argument(1).evaluate().toNumber();
     if (std::isnan(doublePos))
-        return "";
+        return emptyString();
     long pos = static_cast<long>(FunRound::round(doublePos));
     bool haveLength = argumentCount() == 3;
     long len = -1;
     if (haveLength) {
         double doubleLen = argument(2).evaluate().toNumber();
         if (std::isnan(doubleLen))
-            return "";
+            return emptyString();
         len = static_cast<long>(FunRound::round(doubleLen));
     }
 
     if (pos > long(s.length())) 
-        return "";
+        return emptyString();
 
     if (pos < 1) {
         if (haveLength) {
             len -= 1 - pos;
             if (len < 1)
-                return "";
+                return emptyString();
         }
         pos = 1;
     }
@@ -669,62 +661,78 @@ Value FunRound::evaluate() const
     return round(argument(0).evaluate().toNumber());
 }
 
-struct FunctionMapping {
-    const char* name;
-    FunctionRec function;
+struct FunctionMapValue {
+    std::unique_ptr<Function> (*creationFunction)();
+    Interval argumentCountInterval;
 };
 
-static void createFunctionMap()
+static void populateFunctionMap(HashMap<String, FunctionMapValue>& functionMap)
 {
+    struct FunctionMapping {
+        const char* name;
+        FunctionMapValue function;
+    };
+
     static const FunctionMapping functions[] = {
-        { "boolean", { &createFunBoolean, 1 } },
-        { "ceiling", { &createFunCeiling, 1 } },
-        { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
-        { "contains", { &createFunContains, 2 } },
-        { "count", { &createFunCount, 1 } },
-        { "false", { &createFunFalse, 0 } },
-        { "floor", { &createFunFloor, 1 } },
-        { "id", { &createFunId, 1 } },
-        { "lang", { &createFunLang, 1 } },
-        { "last", { &createFunLast, 0 } },
-        { "local-name", { &createFunLocalName, Interval(0, 1) } },
-        { "name", { &createFunName, Interval(0, 1) } },
-        { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
-        { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
-        { "not", { &createFunNot, 1 } },
-        { "number", { &createFunNumber, Interval(0, 1) } },
-        { "position", { &createFunPosition, 0 } },
-        { "round", { &createFunRound, 1 } },
-        { "starts-with", { &createFunStartsWith, 2 } },
-        { "string", { &createFunString, Interval(0, 1) } },
-        { "string-length", { &createFunStringLength, Interval(0, 1) } },
-        { "substring", { &createFunSubstring, Interval(2, 3) } },
-        { "substring-after", { &createFunSubstringAfter, 2 } },
-        { "substring-before", { &createFunSubstringBefore, 2 } },
-        { "sum", { &createFunSum, 1 } },
-        { "translate", { &createFunTranslate, 3 } },
-        { "true", { &createFunTrue, 0 } },
+        { "boolean", { createFunctionBoolean, 1 } },
+        { "ceiling", { createFunctionCeiling, 1 } },
+        { "concat", { createFunctionConcat, Interval(2, Interval::Inf) } },
+        { "contains", { createFunctionContains, 2 } },
+        { "count", { createFunctionCount, 1 } },
+        { "false", { createFunctionFalse, 0 } },
+        { "floor", { createFunctionFloor, 1 } },
+        { "id", { createFunctionId, 1 } },
+        { "lang", { createFunctionLang, 1 } },
+        { "last", { createFunctionLast, 0 } },
+        { "local-name", { createFunctionLocalName, Interval(0, 1) } },
+        { "name", { createFunctionName, Interval(0, 1) } },
+        { "namespace-uri", { createFunctionNamespaceURI, Interval(0, 1) } },
+        { "normalize-space", { createFunctionNormalizeSpace, Interval(0, 1) } },
+        { "not", { createFunctionNot, 1 } },
+        { "number", { createFunctionNumber, Interval(0, 1) } },
+        { "position", { createFunctionPosition, 0 } },
+        { "round", { createFunctionRound, 1 } },
+        { "starts-with", { createFunctionStartsWith, 2 } },
+        { "string", { createFunctionString, Interval(0, 1) } },
+        { "string-length", { createFunctionStringLength, Interval(0, 1) } },
+        { "substring", { createFunctionSubstring, Interval(2, 3) } },
+        { "substring-after", { createFunctionSubstringAfter, 2 } },
+        { "substring-before", { createFunctionSubstringBefore, 2 } },
+        { "sum", { createFunctionSum, 1 } },
+        { "translate", { createFunctionTranslate, 3 } },
+        { "true", { createFunctionTrue, 0 } },
     };
 
-    functionMap = new HashMap<String, FunctionRec>;
     for (size_t i = 0; i < WTF_ARRAY_LENGTH(functions); ++i)
-        functionMap->set(functions[i].name, functions[i].function);
+        functionMap.add(functions[i].name, functions[i].function);
 }
 
-Function* createFunction(const String& name, const Vector<Expression*>& args)
+std::unique_ptr<Function> Function::create(const String& name, unsigned numArguments)
 {
-    if (!functionMap)
-        createFunctionMap();
+    static NeverDestroyed<HashMap<String, FunctionMapValue>> functionMap;
+    if (functionMap.get().isEmpty())
+        populateFunctionMap(functionMap);
 
-    HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name);
-    FunctionRec* functionRec = 0;
+    auto it = functionMap.get().find(name);
+    if (it == functionMap.get().end())
+        return nullptr;
 
-    if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->value)->args.contains(args.size()))
-        return 0;
+    if (!it->value.argumentCountInterval.contains(numArguments))
+        return nullptr;
 
-    Function* function = functionRec->factoryFn();
-    function->setArguments(args);
-    function->setName(name);
+    return it->value.creationFunction();
+}
+
+std::unique_ptr<Function> Function::create(const String& name)
+{
+    return create(name, 0);
+}
+
+std::unique_ptr<Function> Function::create(const String& name, Vector<std::unique_ptr<Expression>> arguments)
+{
+    std::unique_ptr<Function> function = create(name, arguments.size());
+    if (function)
+        function->setArguments(name, std::move(arguments));
     return function;
 }
 
index 9625c88..94347a2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006, 2009 Apple Inc.
+ * Copyright (C) 2006, 2009, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,21 +34,18 @@ namespace XPath {
 
 class Function : public Expression {
 public:
-    void setArguments(const Vector<Expression*>&);
-    void setName(const String& name) { m_name = name; }
+    static std::unique_ptr<Function> create(const String& name);
+    static std::unique_ptr<Function> create(const String& name, Vector<std::unique_ptr<Expression>> arguments);
 
 protected:
-    unsigned argumentCount() const { return subExpressionCount(); }
-    const Expression& argument(int pos) const { return subExpression(pos); }
-
-    String name() const { return m_name; }
+    unsigned argumentCount() const { return subexpressionCount(); }
+    const Expression& argument(unsigned i) const { return subexpression(i); }
 
 private:
-    String m_name;
+    static std::unique_ptr<Function> create(const String& name, unsigned numArguments);
+    void setArguments(const String& name, Vector<std::unique_ptr<Expression>>);
 };
 
-Function* createFunction(const String& name, const Vector<Expression*>& args = Vector<Expression*>());
-
 } // namespace XPath
 } // namespace WebCore
 
index 51204bb..e0c8ee7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
  *
  * Redistribution and use in source and binary forms, with or without
 #include "config.h"
 
 #include "XPathFunctions.h"
-#include "XPathNSResolver.h"
 #include "XPathParser.h"
 #include "XPathPath.h"
-#include "XPathPredicate.h"
-#include "XPathStep.h"
 #include "XPathVariableReference.h"
-#include <wtf/FastMalloc.h>
 
 #define YYMALLOC fastMalloc
 #define YYFREE fastFree
 #define YYDEBUG 0
 #define YYMAXDEPTH 10000
 
+#define YYLEX_PARAM parser
+
 using namespace WebCore;
 using namespace XPath;
 
 %}
 
 %pure_parser
-%parse-param { WebCore::XPath::Parser* parser }
-
-%union
-{
-    Step::Axis axis;
-    Step::NodeTest* nodeTest;
-    NumericOp::Opcode numop;
-    EqTestOp::Opcode eqop;
-    String* str;
-    Expression* expr;
-    Vector<Predicate*>* predList;
-    Vector<Expression*>* argList;
-    Step* step;
-    LocationPath* locationPath;
-}
+%parse-param { Parser& parser }
 
-%{
+%union { NumericOp::Opcode numericOpcode; }
+%left <numericOpcode> MULOP
 
-static int xpathyylex(YYSTYPE* yylval) { return Parser::current()->lex(yylval); }
-static void xpathyyerror(void*, const char*) { }
-    
-%}
+%union { EqTestOp::Opcode equalityTestOpcode; }
+%left <equalityTestOpcode> EQOP RELOP
 
-%left <numop> MULOP
-%left <eqop> EQOP RELOP
 %left PLUS MINUS
+
 %left OR AND
+
+%union { StringImpl* string; }
+%token <string> FUNCTIONNAME LITERAL NAMETEST NUMBER NODETYPE VARIABLEREFERENCE
+%destructor { if ($$) $$->deref(); } FUNCTIONNAME LITERAL NAMETEST NUMBER NODETYPE VARIABLEREFERENCE
+
+%union { Step::Axis axis; }
 %token <axis> AXISNAME
-%token <str> NODETYPE PI FUNCTIONNAME LITERAL
-%token <str> VARIABLEREFERENCE NUMBER
-%token DOTDOT SLASHSLASH
-%token <str> NAMETEST
-%token XPATH_ERROR
-
-%type <locationPath> LocationPath
-%type <locationPath> AbsoluteLocationPath
-%type <locationPath> RelativeLocationPath
-%type <step> Step
 %type <axis> AxisSpecifier
-%type <step> DescendantOrSelf
+
+%token COMMENT DOTDOT PI NODE SLASHSLASH TEXT XPATH_ERROR
+
+%union { LocationPath* locationPath; }
+%type <locationPath> LocationPath AbsoluteLocationPath RelativeLocationPath
+%destructor { delete $$; } LocationPath AbsoluteLocationPath RelativeLocationPath
+
+%union { Step::NodeTest* nodeTest; }
 %type <nodeTest> NodeTest
-%type <expr> Predicate
-%type <predList> OptionalPredicateList
-%type <predList> PredicateList
-%type <step> AbbreviatedStep
-%type <expr> Expr
-%type <expr> PrimaryExpr
-%type <expr> FunctionCall
-%type <argList> ArgumentList
-%type <expr> Argument
-%type <expr> UnionExpr
-%type <expr> PathExpr
-%type <expr> FilterExpr
-%type <expr> OrExpr
-%type <expr> AndExpr
-%type <expr> EqualityExpr
-%type <expr> RelationalExpr
-%type <expr> AdditiveExpr
-%type <expr> MultiplicativeExpr
-%type <expr> UnaryExpr
+%destructor { delete $$; } NodeTest
+
+%union { Vector<std::unique_ptr<Expression>>* expressionVector; }
+%type <expressionVector> ArgumentList PredicateList OptionalPredicateList
+%destructor { delete $$; } ArgumentList PredicateList OptionalPredicateList
+
+%union { Step* step; }
+%type <step> Step AbbreviatedStep DescendantOrSelf
+%destructor { delete $$; } Step AbbreviatedStep DescendantOrSelf
+
+%union { Expression* expression; }
+%type <expression> AdditiveExpr AndExpr Argument EqualityExpr Expr FilterExpr FunctionCall MultiplicativeExpr OrExpr PathExpr Predicate PrimaryExpr RelationalExpr UnaryExpr UnionExpr
+%destructor { delete $$; } AdditiveExpr AndExpr Argument EqualityExpr Expr FilterExpr FunctionCall MultiplicativeExpr OrExpr PathExpr Predicate PrimaryExpr RelationalExpr UnaryExpr UnionExpr
+
+%{
+
+static int xpathyylex(YYSTYPE* yylval, Parser& parser) { return parser.lex(*yylval); }
+static void xpathyyerror(Parser&, const char*) { }
+
+%}
 
 %%
 
-Expr:
-    OrExpr
+Top:
+    Expr
     {
-        parser->m_topExpr = $1;
+        parser.setParseResult(std::unique_ptr<Expression>($1));
     }
     ;
 
+Expr:
+    OrExpr
+    ;
+
 LocationPath:
-    RelativeLocationPath
-    {
-        $$->setAbsolute(false);
-    }
-    |
     AbsoluteLocationPath
     {
-        $$->setAbsolute(true);
+        $$->setAbsolute();
     }
+    |
+    RelativeLocationPath
     ;
 
 AbsoluteLocationPath:
     '/'
     {
         $$ = new LocationPath;
-        parser->registerParseNode($$);
     }
     |
     '/' RelativeLocationPath
@@ -149,8 +135,7 @@ AbsoluteLocationPath:
     DescendantOrSelf RelativeLocationPath
     {
         $$ = $2;
-        $$->insertFirstStep($1);
-        parser->unregisterParseNode($1);
+        $$->prependStep(std::unique_ptr<Step>($1));
     }
     ;
 
@@ -158,83 +143,75 @@ RelativeLocationPath:
     Step
     {
         $$ = new LocationPath;
-        $$->appendStep($1);
-        parser->unregisterParseNode($1);
-        parser->registerParseNode($$);
+        $$->appendStep(std::unique_ptr<Step>($1));
     }
     |
     RelativeLocationPath '/' Step
     {
-        $$->appendStep($3);
-        parser->unregisterParseNode($3);
+        $$->appendStep(std::unique_ptr<Step>($3));
     }
     |
     RelativeLocationPath DescendantOrSelf Step
     {
-        $$->appendStep($2);
-        $$->appendStep($3);
-        parser->unregisterParseNode($2);
-        parser->unregisterParseNode($3);
+        $$->appendStep(std::unique_ptr<Step>($2));
+        $$->appendStep(std::unique_ptr<Step>($3));
     }
     ;
 
 Step:
     NodeTest OptionalPredicateList
     {
-        if ($2) {
-            $$ = new Step(Step::ChildAxis, *$1, *$2);
-            parser->deletePredicateVector($2);
-        } else
-            $$ = new Step(Step::ChildAxis, *$1);
-        parser->deleteNodeTest($1);
-        parser->registerParseNode($$);
+        std::unique_ptr<Vector<std::unique_ptr<Expression>>> predicateList($2);
+        if (predicateList)
+            $$ = new Step(Step::ChildAxis, std::move(*$1), std::move(*predicateList));
+        else
+            $$ = new Step(Step::ChildAxis, std::move(*$1));
     }
     |
     NAMETEST OptionalPredicateList
     {
+        String nametest = adoptRef($1);
+        std::unique_ptr<Vector<std::unique_ptr<Expression>>> predicateList($2);
+
         String localName;
         String namespaceURI;
-        if (!parser->expandQName(*$1, localName, namespaceURI)) {
-            parser->m_gotNamespaceError = true;
+        if (!parser.expandQualifiedName(nametest, localName, namespaceURI)) {
+            $$ = nullptr;
             YYABORT;
         }
-        
-        if ($2) {
-            $$ = new Step(Step::ChildAxis, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI), *$2);
-            parser->deletePredicateVector($2);
-        } else
+
+        if (predicateList)
+            $$ = new Step(Step::ChildAxis, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI), std::move(*predicateList));
+        else
             $$ = new Step(Step::ChildAxis, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI));
-        parser->deleteString($1);
-        parser->registerParseNode($$);
     }
     |
     AxisSpecifier NodeTest OptionalPredicateList
     {
-        if ($3) {
-            $$ = new Step($1, *$2, *$3);
-            parser->deletePredicateVector($3);
-        } else
-            $$ = new Step($1, *$2);
-        parser->deleteNodeTest($2);
-        parser->registerParseNode($$);
+        std::unique_ptr<Vector<std::unique_ptr<Expression>>> predicateList($3);
+
+        if (predicateList)
+            $$ = new Step($1, std::move(*$2), std::move(*predicateList));
+        else
+            $$ = new Step($1, std::move(*$2));
     }
     |
     AxisSpecifier NAMETEST OptionalPredicateList
     {
+        String nametest = adoptRef($2);
+        std::unique_ptr<Vector<std::unique_ptr<Expression>>> predicateList($3);
+
         String localName;
         String namespaceURI;
-        if (!parser->expandQName(*$2, localName, namespaceURI)) {
-            parser->m_gotNamespaceError = true;
+        if (!parser.expandQualifiedName(nametest, localName, namespaceURI)) {
+            $$ = nullptr;
             YYABORT;
         }
 
-        if ($3) {
-            $$ = new Step($1, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI), *$3);
-            parser->deletePredicateVector($3);
-        } else
+        if (predicateList)
+            $$ = new Step($1, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI), std::move(*predicateList));
+        else
             $$ = new Step($1, Step::NodeTest(Step::NodeTest::NameTest, localName, namespaceURI));
-        parser->deleteString($2);
-        parser->registerParseNode($$);
     }
     |
     AbbreviatedStep
@@ -250,37 +227,37 @@ AxisSpecifier:
     ;
 
 NodeTest:
-    NODETYPE '(' ')'
+    NODE '(' ')'
     {
-        if (*$1 == "node")
-            $$ = new Step::NodeTest(Step::NodeTest::AnyNodeTest);
-        else if (*$1 == "text")
-            $$ = new Step::NodeTest(Step::NodeTest::TextNodeTest);
-        else if (*$1 == "comment")
-            $$ = new Step::NodeTest(Step::NodeTest::CommentNodeTest);
-
-        parser->deleteString($1);
-        parser->registerNodeTest($$);
+        $$ = new Step::NodeTest(Step::NodeTest::AnyNodeTest);
+    }
+    |
+    TEXT '(' ')'
+    {
+        $$ = new Step::NodeTest(Step::NodeTest::TextNodeTest);
+    }
+    |
+    COMMENT '(' ')'
+    {
+        $$ = new Step::NodeTest(Step::NodeTest::CommentNodeTest);
     }
     |
     PI '(' ')'
     {
         $$ = new Step::NodeTest(Step::NodeTest::ProcessingInstructionNodeTest);
-        parser->registerNodeTest($$);
     }
     |
     PI '(' LITERAL ')'
     {
-        $$ = new Step::NodeTest(Step::NodeTest::ProcessingInstructionNodeTest, $3->stripWhiteSpace());
-        parser->deleteString($3);
-        parser->registerNodeTest($$);
+        String literal = adoptRef($3);
+        $$ = new Step::NodeTest(Step::NodeTest::ProcessingInstructionNodeTest, literal.stripWhiteSpace());
     }
     ;
 
 OptionalPredicateList:
     /* empty */
     {
-        $$ = 0;
+        $$ = nullptr;
     }
     |
     PredicateList
@@ -289,16 +266,14 @@ OptionalPredicateList:
 PredicateList:
     Predicate
     {
-        $$ = new Vector<Predicate*>;
-        $$->append(new Predicate($1));
-        parser->unregisterParseNode($1);
-        parser->registerPredicateVector($$);
+        $$ = new Vector<std::unique_ptr<Expression>>;
+        $$->append(std::unique_ptr<Expression>($1));
     }
     |
     PredicateList Predicate
     {
-        $$->append(new Predicate($2));
-        parser->unregisterParseNode($2);
+        $$ = $1;
+        $$->append(std::unique_ptr<Expression>($2));
     }
     ;
 
@@ -313,7 +288,6 @@ DescendantOrSelf:
     SLASHSLASH
     {
         $$ = new Step(Step::DescendantOrSelfAxis, Step::NodeTest(Step::NodeTest::AnyNodeTest));
-        parser->registerParseNode($$);
     }
     ;
 
@@ -321,22 +295,19 @@ AbbreviatedStep:
     '.'
     {
         $$ = new Step(Step::SelfAxis, Step::NodeTest(Step::NodeTest::AnyNodeTest));
-        parser->registerParseNode($$);
     }
     |
     DOTDOT
     {
         $$ = new Step(Step::ParentAxis, Step::NodeTest(Step::NodeTest::AnyNodeTest));
-        parser->registerParseNode($$);
     }
     ;
 
 PrimaryExpr:
     VARIABLEREFERENCE
     {
-        $$ = new VariableReference(*$1);
-        parser->deleteString($1);
-        parser->registerParseNode($$);
+        String name = adoptRef($1);
+        $$ = new VariableReference(name);
     }
     |
     '(' Expr ')'
@@ -346,16 +317,14 @@ PrimaryExpr:
     |
     LITERAL
     {
-        $$ = new StringExpression(*$1);
-        parser->deleteString($1);
-        parser->registerParseNode($$);
+        String literal = adoptRef($1);
+        $$ = new StringExpression(std::move(literal));
     }
     |
     NUMBER
     {
-        $$ = new Number($1->toDouble());
-        parser->deleteString($1);
-        parser->registerParseNode($$);
+        String numeral = adoptRef($1);
+        $$ = new Number(numeral.toDouble());
     }
     |
     FunctionCall
@@ -364,37 +333,32 @@ PrimaryExpr:
 FunctionCall:
     FUNCTIONNAME '(' ')'
     {
-        $$ = createFunction(*$1);
+        String name = adoptRef($1);
+        $$ = XPath::Function::create(name).release();
         if (!$$)
             YYABORT;
-        parser->deleteString($1);
-        parser->registerParseNode($$);
     }
     |
     FUNCTIONNAME '(' ArgumentList ')'
     {
-        $$ = createFunction(*$1, *$3);
+        String name = adoptRef($1);
+        $$ = XPath::Function::create(name, std::move(*$3)).release();
         if (!$$)
             YYABORT;
-        parser->deleteString($1);
-        parser->deleteExpressionVector($3);
-        parser->registerParseNode($$);
     }
     ;
 
 ArgumentList:
     Argument
     {
-        $$ = new Vector<Expression*>;
-        $$->append($1);
-        parser->unregisterParseNode($1);
-        parser->registerExpressionVector($$);
+        $$ = new Vector<std::unique_ptr<Expression>>;
+        $$->append(std::unique_ptr<Expression>($1));
     }
     |
     ArgumentList ',' Argument
     {
-        $$->append($3);
-        parser->unregisterParseNode($3);
+        $$ = $1;
+        $$->append(std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -407,41 +371,26 @@ UnionExpr:
     |
     UnionExpr '|' PathExpr
     {
-        $$ = new Union;
-        $$->addSubExpression($1);
-        $$->addSubExpression($3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new Union(std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
 PathExpr:
     LocationPath
-    {
-        $$ = $1;
-    }
     |
     FilterExpr
     |
     FilterExpr '/' RelativeLocationPath
     {
-        $3->setAbsolute(true);
-        $$ = new Path(static_cast<Filter*>($1), $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $3->setAbsolute();
+        $$ = new Path(std::unique_ptr<Expression>($1), std::unique_ptr<LocationPath>($3));
     }
     |
     FilterExpr DescendantOrSelf RelativeLocationPath
     {
-        $3->insertFirstStep($2);
-        $3->setAbsolute(true);
-        $$ = new Path(static_cast<Filter*>($1), $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($2);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $3->prependStep(std::unique_ptr<Step>($2));
+        $3->setAbsolute();
+        $$ = new Path(std::unique_ptr<Expression>($1), std::unique_ptr<LocationPath>($3));
     }
     ;
 
@@ -450,10 +399,8 @@ FilterExpr:
     |
     PrimaryExpr PredicateList
     {
-        $$ = new Filter($1, *$2);
-        parser->unregisterParseNode($1);
-        parser->deletePredicateVector($2);
-        parser->registerParseNode($$);
+        std::unique_ptr<Vector<std::unique_ptr<Expression>>> predicateList($2);
+        $$ = new Filter(std::unique_ptr<Expression>($1), std::move(*predicateList));
     }
     ;
 
@@ -462,10 +409,7 @@ OrExpr:
     |
     OrExpr OR AndExpr
     {
-        $$ = new LogicalOp(LogicalOp::OP_Or, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new LogicalOp(LogicalOp::OP_Or, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -474,10 +418,7 @@ AndExpr:
     |
     AndExpr AND EqualityExpr
     {
-        $$ = new LogicalOp(LogicalOp::OP_And, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new LogicalOp(LogicalOp::OP_And, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -486,10 +427,7 @@ EqualityExpr:
     |
     EqualityExpr EQOP RelationalExpr
     {
-        $$ = new EqTestOp($2, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new EqTestOp($2, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -498,10 +436,7 @@ RelationalExpr:
     |
     RelationalExpr RELOP AdditiveExpr
     {
-        $$ = new EqTestOp($2, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new EqTestOp($2, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -510,18 +445,12 @@ AdditiveExpr:
     |
     AdditiveExpr PLUS MultiplicativeExpr
     {
-        $$ = new NumericOp(NumericOp::OP_Add, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new NumericOp(NumericOp::OP_Add, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     |
     AdditiveExpr MINUS MultiplicativeExpr
     {
-        $$ = new NumericOp(NumericOp::OP_Sub, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new NumericOp(NumericOp::OP_Sub, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -530,10 +459,7 @@ MultiplicativeExpr:
     |
     MultiplicativeExpr MULOP UnaryExpr
     {
-        $$ = new NumericOp($2, $1, $3);
-        parser->unregisterParseNode($1);
-        parser->unregisterParseNode($3);
-        parser->registerParseNode($$);
+        $$ = new NumericOp($2, std::unique_ptr<Expression>($1), std::unique_ptr<Expression>($3));
     }
     ;
 
@@ -542,10 +468,7 @@ UnaryExpr:
     |
     MINUS UnaryExpr
     {
-        $$ = new Negative;
-        $$->addSubExpression($2);
-        parser->unregisterParseNode($2);
-        parser->registerParseNode($$);
+        $$ = new Negative(std::unique_ptr<Expression>($2));
     }
     ;
 
index 87782d4..e5a6a92 100644 (file)
@@ -44,7 +44,7 @@ static inline Node* parentWithDepth(unsigned depth, const Vector<Node*>& parents
     return parents[parents.size() - 1 - depth];
 }
 
-static void sortBlock(unsigned from, unsigned to, Vector<Vector<Node*> >& parentMatrix, bool mayContainAttributeNodes)
+static void sortBlock(unsigned from, unsigned to, Vector<Vector<Node*>>& parentMatrix, bool mayContainAttributeNodes)
 {
     ASSERT(from + 1 < to); // Should not call this function with less that two nodes to sort.
     unsigned minDepth = UINT_MAX;
@@ -142,7 +142,7 @@ void NodeSet::sort() const
 
     unsigned nodeCount = m_nodes.size();
     if (nodeCount < 2) {
-        const_cast<bool&>(m_isSorted) = true;
+        m_isSorted = true;
         return;
     }
 
@@ -169,12 +169,13 @@ void NodeSet::sort() const
     sortBlock(0, nodeCount, parentMatrix, containsAttributeNodes);
     
     // It is not possible to just assign the result to m_nodes, because some nodes may get dereferenced and destroyed.
-    Vector<RefPtr<Node> > sortedNodes;
+    Vector<RefPtr<Node>> sortedNodes;
     sortedNodes.reserveInitialCapacity(nodeCount);
     for (unsigned i = 0; i < nodeCount; ++i)
         sortedNodes.append(parentMatrix[i][0]);
     
-    const_cast<Vector<RefPtr<Node> >&>(m_nodes).swap(sortedNodes);
+    m_nodes = std::move(sortedNodes);
+    m_isSorted = true;
 }
 
 static Node* findRootNode(Node* node)
@@ -227,27 +228,14 @@ void NodeSet::traversalSort() const
     }
 
     ASSERT(sortedNodes.size() == nodeCount);
-    const_cast<Vector<RefPtr<Node> >&>(m_nodes).swap(sortedNodes);
-}
-
-void NodeSet::reverse()
-{
-    if (m_nodes.isEmpty())
-        return;
-
-    unsigned from = 0;
-    unsigned to = m_nodes.size() - 1;
-    while (from < to) {
-        m_nodes[from].swap(m_nodes[to]);
-        ++from;
-        --to;
-    }
+    m_nodes = std::move(sortedNodes);
+    m_isSorted = true;
 }
 
 Node* NodeSet::firstNode() const
 {
     if (isEmpty())
-        return 0;
+        return nullptr;
 
     sort(); // FIXME: fully sorting the node-set just to find its first node is wasteful.
     return m_nodes.at(0).get();
@@ -256,7 +244,7 @@ Node* NodeSet::firstNode() const
 Node* NodeSet::anyNode() const
 {
     if (isEmpty())
-        return 0;
+        return nullptr;
 
     return m_nodes.at(0).get();
 }
index 839be8d..459fcf3 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -26,9 +27,6 @@
 #ifndef XPathNodeSet_h
 #define XPathNodeSet_h
 
-#include <wtf/Vector.h>
-#include <wtf/Forward.h>
-
 #include "Node.h"
 
 namespace WebCore {
@@ -36,26 +34,24 @@ namespace WebCore {
     namespace XPath {
 
         class NodeSet {
-            WTF_MAKE_FAST_ALLOCATED;
         public:
             NodeSet() : m_isSorted(true), m_subtreesAreDisjoint(false) { }
+            explicit NodeSet(PassRefPtr<Node> node) : m_isSorted(true), m_subtreesAreDisjoint(false), m_nodes(1, node) { }
             
             size_t size() const { return m_nodes.size(); }
-            bool isEmpty() const { return !m_nodes.size(); }
+            bool isEmpty() const { return m_nodes.isEmpty(); }
             Node* operator[](unsigned i) const { return m_nodes.at(i).get(); }
             void reserveCapacity(size_t newCapacity) { m_nodes.reserveCapacity(newCapacity); }
             void clear() { m_nodes.clear(); }
-            void swap(NodeSet& other) { std::swap(m_isSorted, other.m_isSorted); std::swap(m_subtreesAreDisjoint, other.m_subtreesAreDisjoint); m_nodes.swap(other.m_nodes); }
 
             // NodeSet itself does not verify that nodes in it are unique.
-            void append(Node* node) { m_nodes.append(node); }
             void append(PassRefPtr<Node> node) { m_nodes.append(node); }
             void append(const NodeSet& nodeSet) { m_nodes.appendVector(nodeSet.m_nodes); }
 
-            // Returns the set's first node in document order, or 0 if the set is empty.
+            // Returns the set's first node in document order, or nullptr if the set is empty.
             Node* firstNode() const;
 
-            // Returns 0 if the set is empty.
+            // Returns nullptr if the set is empty.
             Node* anyNode() const;
 
             // NodeSet itself doesn't check if it contains nodes in document order - the caller should tell it if it does not.
@@ -68,14 +64,12 @@ namespace WebCore {
             void markSubtreesDisjoint(bool disjoint) { m_subtreesAreDisjoint = disjoint; }
             bool subtreesAreDisjoint() const { return m_subtreesAreDisjoint || m_nodes.size() < 2; }
 
-            void reverse();
-        
         private:
             void traversalSort() const;
 
-            bool m_isSorted;
+            mutable bool m_isSorted;
             bool m_subtreesAreDisjoint;
-            Vector<RefPtr<Node> > m_nodes;
+            mutable Vector<RefPtr<Node>> m_nodes;
         };
 
     }
index a03f1fe..826985b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Maksim Orlovich <maksim@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
  *
  * Redistribution and use in source and binary forms, with or without
 #include "XPathNSResolver.h"
 #include "XPathPath.h"
 #include "XPathStep.h"
+#include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/text/StringHash.h>
 
 using namespace WebCore;
-using namespace WTF;
-using namespace Unicode;
 using namespace XPath;
 
-extern int xpathyyparse(WebCore::XPath::Parser*);
+extern int xpathyyparse(Parser&);
+
 #include "XPathGrammar.h"
 
-Parser* Parser::currentParser = 0;
+namespace WebCore {
+namespace XPath {
 
-enum XMLCat { NameStart, NameCont, NotPartOfName };
+struct Parser::Token {
+    int type;
+    String string;
+    Step::Axis axis;
+    NumericOp::Opcode numericOpcode;
+    EqTestOp::Opcode equalityTestOpcode;
 
-typedef HashMap<String, Step::Axis> AxisNamesMap;
+    Token(int type) : type(type) { }
+    Token(int type, const String& string) : type(type), string(string) { }
+    Token(int type, Step::Axis axis) : type(type), axis(axis) { }
+    Token(int type, NumericOp::Opcode opcode) : type(type), numericOpcode(opcode) { }
+    Token(int type, EqTestOp::Opcode opcode) : type(type), equalityTestOpcode(opcode) { }
+};
+
+enum XMLCat { NameStart, NameCont, NotPartOfName };
 
 static XMLCat charCat(UChar aChar)
 {
-    //### might need to add some special cases from the XML spec.
+    using namespace WTF;
+    using namespace Unicode;
 
     if (aChar == '_')
         return NameStart;
@@ -68,7 +82,7 @@ static XMLCat charCat(UChar aChar)
     return NotPartOfName;
 }
 
-static void setUpAxisNamesMap(AxisNamesMap& axisNames)
+static void populateAxisNamesMap(HashMap<String, Step::Axis>& axisNames)
 {
     struct AxisName {
         const char* name;
@@ -89,29 +103,23 @@ static void setUpAxisNamesMap(AxisNamesMap& axisNames)
         { "preceding-sibling", Step::PrecedingSiblingAxis },
         { "self", Step::SelfAxis }
     };
-    for (unsigned i = 0; i < sizeof(axisNameList) / sizeof(axisNameList[0]); ++i)
-        axisNames.set(axisNameList[i].name, axisNameList[i].axis);
+    for (unsigned i = 0; i < WTF_ARRAY_LENGTH(axisNameList); ++i)
+        axisNames.add(axisNameList[i].name, axisNameList[i].axis);
 }
 
-static bool isAxisName(const String& name, Step::Axis& type)
+static bool parseAxisName(const String& name, Step::Axis& type)
 {
-    DEFINE_STATIC_LOCAL(AxisNamesMap, axisNames, ());
-
-    if (axisNames.isEmpty())
-        setUpAxisNamesMap(axisNames);
+    static NeverDestroyed<HashMap<String, Step::Axis>> axisNames;
+    if (axisNames.get().isEmpty())
+        populateAxisNamesMap(axisNames);
 
-    AxisNamesMap::iterator it = axisNames.find(name);
-    if (it == axisNames.end())
+    auto it = axisNames.get().find(name);
+    if (it == axisNames.get().end())
         return false;
     type = it->value;
     return true;
 }
 
-static bool isNodeTypeName(const String& name)
-{
-    return name == "comment" || name == "text" || name == "processing-instruction" || name == "node";
-}
-
 // Returns whether the current token can possibly be a binary operator, given
 // the previous token. Necessary to disambiguate some of the operators
 // (* (multiply), div, and, or, mod) in the [32] Operator rule
@@ -136,25 +144,25 @@ void Parser::skipWS()
         ++m_nextPos;
 }
 
-Token Parser::makeTokenAndAdvance(int code, int advance)
+Parser::Token Parser::makeTokenAndAdvance(int code, int advance)
 {
     m_nextPos += advance;
     return Token(code);
 }
 
-Token Parser::makeTokenAndAdvance(int code, NumericOp::Opcode val, int advance)
+Parser::Token Parser::makeTokenAndAdvance(int code, NumericOp::Opcode val, int advance)
 {
     m_nextPos += advance;
     return Token(code, val);
 }
 
-Token Parser::makeTokenAndAdvance(int code, EqTestOp::Opcode val, int advance)
+Parser::Token Parser::makeTokenAndAdvance(int code, EqTestOp::Opcode val, int advance)
 {
     m_nextPos += advance;
     return Token(code, val);
 }
 
-// Returns next char if it's there and interesting, 0 otherwise
+// Returns next char if it's there and interesting, 0 otherwise.
 char Parser::peekAheadHelper()
 {
     if (m_nextPos + 1 >= m_data.length())
@@ -175,7 +183,7 @@ char Parser::peekCurHelper()
     return next;
 }
 
-Token Parser::lexString()
+Parser::Token Parser::lexString()
 {
     UChar delimiter = m_data[m_nextPos];
     int startPos = m_nextPos + 1;
@@ -194,7 +202,7 @@ Token Parser::lexString()
     return Token(XPATH_ERROR);
 }
 
-Token Parser::lexNumber()
+Parser::Token Parser::lexNumber()
 {
     int startPos = m_nextPos;
     bool seenDot = false;
@@ -256,7 +264,7 @@ bool Parser::lexQName(String& name)
     return true;
 }
 
-Token Parser::nextTokenInternal()
+inline Parser::Token Parser::nextTokenInternal()
 {
     skipWS();
 
@@ -344,7 +352,7 @@ Token Parser::nextTokenInternal()
             
             //It might be an axis name.
             Step::Axis axis;
-            if (isAxisName(name, axis))
+            if (parseAxisName(name, axis))
                 return Token(AXISNAME, axis);
             // Ugh, :: is only valid in axis names -> error
             return Token(XPATH_ERROR);
@@ -370,13 +378,16 @@ Token Parser::nextTokenInternal()
     if (peekCurHelper() == '(') {
         // note: we don't swallow the '(' here!
 
-        // either node type of function name
-        if (isNodeTypeName(name)) {
-            if (name == "processing-instruction")
-                return Token(PI);
+        // Either node type oor function name.
 
-            return Token(NODETYPE, name);
-        }
+        if (name == "processing-instruction")
+            return Token(PI);
+        if (name == "node")
+            return Token(NODE);
+        if (name == "text")
+            return Token(TEXT);
+        if (name == "comment")
+            return Token(COMMENT);
 
         return Token(FUNCTIONNAME, name);
     }
@@ -385,47 +396,36 @@ Token Parser::nextTokenInternal()
     return Token(NAMETEST, name);
 }
 
-Token Parser::nextToken()
+inline Parser::Token Parser::nextToken()
 {
-    Token toRet = nextTokenInternal();
-    m_lastTokenType = toRet.type;
-    return toRet;
+    Token token = nextTokenInternal();
+    m_lastTokenType = token.type;
+    return token;
 }
 
-Parser::Parser()
+Parser::Parser(const String& statement, XPathNSResolver* resolver)
+    : m_data(statement)
+    , m_resolver(resolver)
+    , m_nextPos(0)
+    , m_lastTokenType(0)
+    , m_sawNamespaceError(false)
 {
-    reset(String());
 }
 
-Parser::~Parser()
+int Parser::lex(YYSTYPE& yylval)
 {
-}
-
-void Parser::reset(const String& data)
-{
-    m_nextPos = 0;
-    m_data = data;
-    m_lastTokenType = 0;
-    
-    m_topExpr = 0;
-    m_gotNamespaceError = false;
-}
+    Token token = nextToken();
 
-int Parser::lex(void* data)
-{
-    YYSTYPE* yylval = static_cast<YYSTYPE*>(data);
-    Token tok = nextToken();
-
-    switch (tok.type) {
+    switch (token.type) {
     case AXISNAME:
-        yylval->axis = tok.axis;
+        yylval.axis = token.axis;
         break;
     case MULOP:
-        yylval->numop = tok.numop;
+        yylval.numericOpcode = token.numericOpcode;
         break;
     case RELOP:
     case EQOP:
-        yylval->eqop = tok.eqop;
+        yylval.equalityTestOpcode = token.equalityTestOpcode;
         break;
     case NODETYPE:
     case FUNCTIONNAME:
@@ -433,190 +433,50 @@ int Parser::lex(void* data)
     case VARIABLEREFERENCE:
     case NUMBER:
     case NAMETEST:
-        yylval->str = new String(tok.str);
-        registerString(yylval->str);
+        yylval.string = token.string.releaseImpl().leakRef();
         break;
     }
 
-    return tok.type;
+    return token.type;
 }
 
-bool Parser::expandQName(const String& qName, String& localName, String& namespaceURI)
+bool Parser::expandQualifiedName(const String& qualifiedName, String& localName, String& namespaceURI)
 {
-    size_t colon = qName.find(':');
+    size_t colon = qualifiedName.find(':');
     if (colon != notFound) {
-        if (!m_resolver)
+        if (!m_resolver) {
+            m_sawNamespaceError = true;
             return false;
-        namespaceURI = m_resolver->lookupNamespaceURI(qName.left(colon));
-        if (namespaceURI.isNull())
+        }
+        namespaceURI = m_resolver->lookupNamespaceURI(qualifiedName.left(colon));
+        if (namespaceURI.isNull()) {
+            m_sawNamespaceError = true;
             return false;
-        localName = qName.substring(colon + 1);
+        }
+        localName = qualifiedName.substring(colon + 1);
     } else
-        localName = qName;
-    
+        localName = qualifiedName;
+
     return true;
 }
 
-Expression* Parser::parseStatement(const String& statement, PassRefPtr<XPathNSResolver> resolver, ExceptionCode& ec)
+std::unique_ptr<Expression> Parser::parseStatement(const String& statement, XPathNSResolver* resolver, ExceptionCode& ec)
 {
-    reset(statement);
-
-    m_resolver = resolver;
-    
-    Parser* oldParser = currentParser;
-    currentParser = this;
-    int parseError = xpathyyparse(this);
-    currentParser = oldParser;
-
-    if (parseError) {
-        deleteAllValues(m_parseNodes);
-        m_parseNodes.clear();
-
-        HashSet<Vector<Predicate*>*>::iterator pend = m_predicateVectors.end();
-        for (HashSet<Vector<Predicate*>*>::iterator it = m_predicateVectors.begin(); it != pend; ++it) {
-            deleteAllValues(**it);
-            delete *it;
-        }
-        m_predicateVectors.clear();
-
-        HashSet<Vector<Expression*>*>::iterator eend = m_expressionVectors.end();
-        for (HashSet<Vector<Expression*>*>::iterator it = m_expressionVectors.begin(); it != eend; ++it) {
-            deleteAllValues(**it);
-            delete *it;
-        }
-        m_expressionVectors.clear();
-
-        deleteAllValues(m_strings);
-        m_strings.clear();
+    Parser parser(statement, resolver);
 
-        deleteAllValues(m_nodeTests);
-        m_nodeTests.clear();
+    int parseError = xpathyyparse(parser);
 
-        m_topExpr = 0;
-
-        if (m_gotNamespaceError)
-            ec = NAMESPACE_ERR;
-        else
-            ec = XPathException::INVALID_EXPRESSION_ERR;
-        return 0;
+    if (parser.m_sawNamespaceError) {
+        ec = NAMESPACE_ERR;
+        return nullptr;
     }
 
-    ASSERT(m_parseNodes.size() == 1);
-    ASSERT(*m_parseNodes.begin() == m_topExpr);
-    ASSERT(m_expressionVectors.size() == 0);
-    ASSERT(m_predicateVectors.size() == 0);
-    ASSERT(m_strings.size() == 0);
-    ASSERT(m_nodeTests.size() == 0);
-
-    m_parseNodes.clear();
-    Expression* result = m_topExpr;
-    m_topExpr = 0;
-
-    return result;
-}
-
-void Parser::registerParseNode(ParseNode* node)
-{
-    if (node == 0)
-        return;
-    
-    ASSERT(!m_parseNodes.contains(node));
-    
-    m_parseNodes.add(node);
-}
-
-void Parser::unregisterParseNode(ParseNode* node)
-{
-    if (node == 0)
-        return;
-    
-    ASSERT(m_parseNodes.contains(node));
-
-    m_parseNodes.remove(node);
-}
-
-void Parser::registerPredicateVector(Vector<Predicate*>* vector)
-{
-    if (vector == 0)
-        return;
-
-    ASSERT(!m_predicateVectors.contains(vector));
-    
-    m_predicateVectors.add(vector);
-}
-
-void Parser::deletePredicateVector(Vector<Predicate*>* vector)
-{
-    if (vector == 0)
-        return;
-
-    ASSERT(m_predicateVectors.contains(vector));
-    
-    m_predicateVectors.remove(vector);
-    delete vector;
-}
-
-
-void Parser::registerExpressionVector(Vector<Expression*>* vector)
-{
-    if (vector == 0)
-        return;
-
-    ASSERT(!m_expressionVectors.contains(vector));
-    
-    m_expressionVectors.add(vector);    
-}
-
-void Parser::deleteExpressionVector(Vector<Expression*>* vector)
-{
-    if (vector == 0)
-        return;
-
-    ASSERT(m_expressionVectors.contains(vector));
-    
-    m_expressionVectors.remove(vector);
-    delete vector;
-}
-
-void Parser::registerString(String* s)
-{
-    if (s == 0)
-        return;
-    
-    ASSERT(!m_strings.contains(s));
-    
-    m_strings.add(s);        
-}
-
-void Parser::deleteString(String* s)
-{
-    if (s == 0)
-        return;
-    
-    ASSERT(m_strings.contains(s));
-    
-    m_strings.remove(s);
-    delete s;
-}
-
-void Parser::registerNodeTest(Step::NodeTest* t)
-{
-    if (t == 0)
-        return;
-    
-    ASSERT(!m_nodeTests.contains(t));
-    
-    m_nodeTests.add(t);        
-}
+    if (parseError) {
+        ec = XPathException::INVALID_EXPRESSION_ERR;
+        return nullptr;
+    }
 
-void Parser::deleteNodeTest(Step::NodeTest* t)
-{
-    if (t == 0)
-        return;
-    
-    ASSERT(m_nodeTests.contains(t));
-    
-    m_nodeTests.remove(t);
-    delete t;
+    return std::move(parser.m_result);
 }
 
+} }
index e58c444..4e6f437 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Maksim Orlovich <maksim@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,8 @@
 #include "XPathStep.h"
 #include "XPathPredicate.h"
 
+union YYSTYPE;
+
 namespace WebCore {
 
     typedef int ExceptionCode;
@@ -38,58 +40,20 @@ namespace WebCore {
 
     namespace XPath {
 
-        class Expression;
-        class ParseNode;
-        class Predicate;
-
-        struct Token {
-            int type;
-            String str;
-            Step::Axis axis;
-            NumericOp::Opcode numop;
-            EqTestOp::Opcode eqop;
-            
-            Token(int t) : type(t) {}
-            Token(int t, const String& v): type(t), str(v) {}
-            Token(int t, Step::Axis v): type(t), axis(v) {}
-            Token(int t, NumericOp::Opcode v): type(t), numop(v) {}
-            Token(int t, EqTestOp::Opcode v): type(t), eqop(v) {}
-        };
-
         class Parser {
             WTF_MAKE_NONCOPYABLE(Parser);
         public:
-            Parser();
-            ~Parser();
-
-            XPathNSResolver* resolver() const { return m_resolver.get(); }
-            bool expandQName(const String& qName, String& localName, String& namespaceURI);
-
-            Expression* parseStatement(const String& statement, PassRefPtr<XPathNSResolver>, ExceptionCode&);
-
-            static Parser* current() { return currentParser; }
-
-            int lex(void* yylval);
+            static std::unique_ptr<Expression> parseStatement(const String& statement, XPathNSResolver*, ExceptionCode&);
 
-            Expression* m_topExpr;
-            bool m_gotNamespaceError;
+            int lex(YYSTYPE&);
+            bool expandQualifiedName(const String& qualifiedName, String& localName, String& namespaceURI);
+            void setParseResult(std::unique_ptr<Expression> expression) { m_result = std::move(expression); }
 
-            void registerParseNode(ParseNode*);
-            void unregisterParseNode(ParseNode*);
-
-            void registerPredicateVector(Vector<Predicate*>*);
-            void deletePredicateVector(Vector<Predicate*>*);
-
-            void registerExpressionVector(Vector<Expression*>*);
-            void deleteExpressionVector(Vector<Expression*>*);
-
-            void registerString(String*);
-            void deleteString(String*);
+        private:
+            Parser(const String&, XPathNSResolver*);
 
-            void registerNodeTest(Step::NodeTest*);
-            void deleteNodeTest(Step::NodeTest*);
+            struct Token;
 
-        private:
             bool isBinaryOperatorContext() const;
 
             void skipWS();
@@ -107,20 +71,14 @@ namespace WebCore {
             Token nextToken();
             Token nextTokenInternal();
 
-            void reset(const String& data);
-
-            static Parser* currentParser;
+            const String& m_data;
+            XPathNSResolver* m_resolver;
 
             unsigned m_nextPos;
-            String m_data;
             int m_lastTokenType;
-            RefPtr<XPathNSResolver> m_resolver;
 
-            HashSet<ParseNode*> m_parseNodes;
-            HashSet<Vector<Predicate*>*> m_predicateVectors;
-            HashSet<Vector<Expression*>*> m_expressionVectors;
-            HashSet<String*> m_strings;
-            HashSet<Step::NodeTest*> m_nodeTests;
+            std::unique_ptr<Expression> m_result;
+            bool m_sawNamespaceError;
         };
 
     }
index bc8a63a..660c315 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006, 2009 Apple Inc.
+ * Copyright (C) 2006, 2009, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
  *
  * Redistribution and use in source and binary forms, with or without
 namespace WebCore {
 namespace XPath {
         
-Filter::Filter(Expression* expr, const Vector<Predicate*>& predicates)
-    : m_expr(expr), m_predicates(predicates)
+Filter::Filter(std::unique_ptr<Expression> expression, Vector<std::unique_ptr<Expression>> predicates)
+    : m_expression(std::move(expression)), m_predicates(std::move(predicates))
 {
-    setIsContextNodeSensitive(m_expr->isContextNodeSensitive());
-    setIsContextPositionSensitive(m_expr->isContextPositionSensitive());
-    setIsContextSizeSensitive(m_expr->isContextSizeSensitive());
-}
-
-Filter::~Filter()
-{
-    delete m_expr;
-    deleteAllValues(m_predicates);
+    setIsContextNodeSensitive(m_expression->isContextNodeSensitive());
+    setIsContextPositionSensitive(m_expression->isContextPositionSensitive());
+    setIsContextSizeSensitive(m_expression->isContextSizeSensitive());
 }
 
 Value Filter::evaluate() const
 {
-    Value v = m_expr->evaluate();
+    Value result = m_expression->evaluate();
     
-    NodeSet& nodes = v.modifiableNodeSet();
+    NodeSet& nodes = result.modifiableNodeSet();
     nodes.sort();
 
     EvaluationContext& evaluationContext = Expression::evaluationContext();
@@ -69,26 +63,21 @@ Value Filter::evaluate() const
             evaluationContext.node = node;
             ++evaluationContext.position;
             
-            if (m_predicates[i]->evaluate())
+            if (evaluatePredicate(*m_predicates[i]))
                 newNodes.append(node);
         }
-        nodes.swap(newNodes);
+        nodes = std::move(newNodes);
     }
 
-    return v;
+    return result;
 }
 
 LocationPath::LocationPath()
-    : m_absolute(false)
+    : m_isAbsolute(false)
 {
     setIsContextNodeSensitive(true);
 }
 
-LocationPath::~LocationPath()
-{
-    deleteAllValues(m_steps);
-}
-
 Value LocationPath::evaluate() const
 {
     EvaluationContext& evaluationContext = Expression::evaluationContext();
@@ -102,7 +91,7 @@ Value LocationPath::evaluate() const
     // This is for compatibility with Firefox, and also seems like a more
     // logical treatment of where you would expect the "root" to be.
     Node* context = evaluationContext.node.get();
-    if (m_absolute && context->nodeType() != Node::DOCUMENT_NODE)  {
+    if (m_isAbsolute && !context->isDocumentNode())  {
         if (context->inDocument())
             context = context->ownerDocument();
         else
@@ -114,7 +103,7 @@ Value LocationPath::evaluate() const
     evaluate(nodes);
     
     evaluationContext = backupContext;
-    return Value(nodes, Value::adopt);
+    return Value(std::move(nodes));
 }
 
 void LocationPath::evaluate(NodeSet& nodes) const
@@ -122,23 +111,23 @@ void LocationPath::evaluate(NodeSet& nodes) const
     bool resultIsSorted = nodes.isSorted();
 
     for (unsigned i = 0; i < m_steps.size(); i++) {
-        Step* step = m_steps[i];
+        Step& step = *m_steps[i];
         NodeSet newNodes;
         HashSet<Node*> newNodesSet;
 
-        bool needToCheckForDuplicateNodes = !nodes.subtreesAreDisjoint() || (step->axis() != Step::ChildAxis && step->axis() != Step::SelfAxis
-            && step->axis() != Step::DescendantAxis && step->axis() != Step::DescendantOrSelfAxis && step->axis() != Step::AttributeAxis);
+        bool needToCheckForDuplicateNodes = !nodes.subtreesAreDisjoint() || (step.axis() != Step::ChildAxis && step.axis() != Step::SelfAxis
+            && step.axis() != Step::DescendantAxis && step.axis() != Step::DescendantOrSelfAxis && step.axis() != Step::AttributeAxis);
 
         if (needToCheckForDuplicateNodes)
             resultIsSorted = false;
 
         // This is a simplified check that can be improved to handle more cases.
-        if (nodes.subtreesAreDisjoint() && (step->axis() == Step::ChildAxis || step->axis() == Step::SelfAxis))
+        if (nodes.subtreesAreDisjoint() && (step.axis() == Step::ChildAxis || step.axis() == Step::SelfAxis))
             newNodes.markSubtreesDisjoint(true);
 
         for (unsigned j = 0; j < nodes.size(); j++) {
             NodeSet matches;
-            step->evaluate(nodes[j], matches);
+            step.evaluate(*nodes[j], matches);
 
             if (!matches.isSorted())
                 resultIsSorted = false;
@@ -150,65 +139,56 @@ void LocationPath::evaluate(NodeSet& nodes) const
             }
         }
         
-        nodes.swap(newNodes);
+        nodes = std::move(newNodes);
     }
 
     nodes.markSorted(resultIsSorted);
 }
 
-void LocationPath::appendStep(Step* step)
+void LocationPath::appendStep(std::unique_ptr<Step> step)
 {
     unsigned stepCount = m_steps.size();
     if (stepCount) {
         bool dropSecondStep;
-        optimizeStepPair(m_steps[stepCount - 1], step, dropSecondStep);
-        if (dropSecondStep) {
-            delete step;
+        optimizeStepPair(*m_steps[stepCount - 1], *step, dropSecondStep);
+        if (dropSecondStep)
             return;
-        }
     }
     step->optimize();
-    m_steps.append(step);
+    m_steps.append(std::move(step));
 }
 
-void LocationPath::insertFirstStep(Step* step)
+void LocationPath::prependStep(std::unique_ptr<Step> step)
 {
     if (m_steps.size()) {
         bool dropSecondStep;
-        optimizeStepPair(step, m_steps[0], dropSecondStep);
+        optimizeStepPair(*step, *m_steps[0], dropSecondStep);
         if (dropSecondStep) {
-            delete m_steps[0];
-            m_steps[0] = step;
+            m_steps[0] = std::move(step);
             return;
         }
     }
     step->optimize();
-    m_steps.insert(0, step);
-}
-
-Path::Path(Filter* filter, LocationPath* path)
-    : m_filter(filter)
-    , m_path(path)
-{
-    setIsContextNodeSensitive(filter->isContextNodeSensitive());
-    setIsContextPositionSensitive(filter->isContextPositionSensitive());
-    setIsContextSizeSensitive(filter->isContextSizeSensitive());
+    m_steps.insert(0, std::move(step));
 }
 
-Path::~Path()
+Path::Path(std::unique_ptr<Expression> filter, std::unique_ptr<LocationPath> path)
+    : m_filter(std::move(filter))
+    , m_path(std::move(path))
 {
-    delete m_filter;
-    delete m_path;
+    setIsContextNodeSensitive(m_filter->isContextNodeSensitive());
+    setIsContextPositionSensitive(m_filter->isContextPositionSensitive());
+    setIsContextSizeSensitive(m_filter->isContextSizeSensitive());
 }
 
 Value Path::evaluate() const
 {
-    Value v = m_filter->evaluate();
+    Value result = m_filter->evaluate();
 
-    NodeSet& nodes = v.modifiableNodeSet();
+    NodeSet& nodes = result.modifiableNodeSet();
     m_path->evaluate(nodes);
     
-    return v;
+    return result;
 }
 
 }
index b1a57cb..14e8812 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006, 2009 Apple Inc.
+ * Copyright (C) 2006, 2009, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #define XPathPath_h
 
 #include "XPathExpressionNode.h"
-#include "XPathNodeSet.h"
 
 namespace WebCore {
 
     namespace XPath {
 
-        class Predicate;
         class Step;
 
-        class Filter : public Expression {
+        class Filter FINAL : public Expression {
         public:
-            Filter(Expression*, const Vector<Predicate*>& = Vector<Predicate*>());
-            virtual ~Filter();
-
-            virtual Value evaluate() const;
+            Filter(std::unique_ptr<Expression>, Vector<std::unique_ptr<Expression>> predicates);
 
         private:
-            virtual Value::Type resultType() const { return Value::NodeSetValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
 
-            Expression* m_expr;
-            Vector<Predicate*> m_predicates;
+            std::unique_ptr<Expression> m_expression;
+            Vector<std::unique_ptr<Expression>> m_predicates;
         };
 
-        class LocationPath : public Expression {
+        class LocationPath FINAL : public Expression {
         public:
             LocationPath();
-            virtual ~LocationPath();
-            void setAbsolute(bool value) { m_absolute = value; setIsContextNodeSensitive(!m_absolute); }
 
-            virtual Value evaluate() const;
+            void setAbsolute() { m_isAbsolute = true; setIsContextNodeSensitive(false); }
+
             void evaluate(NodeSet& nodes) const; // nodes is an input/output parameter
 
-            void appendStep(Step* step);
-            void insertFirstStep(Step* step);
+            void appendStep(std::unique_ptr<Step>);
+            void prependStep(std::unique_ptr<Step>);
 
         private:
-            virtual Value::Type resultType() const { return Value::NodeSetValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
 
-            Vector<Step*> m_steps;
-            bool m_absolute;
+            Vector<std::unique_ptr<Step>> m_steps;
+            bool m_isAbsolute;
         };
 
-        class Path : public Expression {
+        class Path FINAL : public Expression {
         public:
-            Path(Filter*, LocationPath*);
-            virtual ~Path();
-
-            virtual Value evaluate() const;
+            Path(std::unique_ptr<Expression> filter, std::unique_ptr<LocationPath>);
 
         private:
-            virtual Value::Type resultType() const { return Value::NodeSetValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
 
-            Filter* m_filter;
-            LocationPath* m_path;
+            std::unique_ptr<Expression> m_filter;
+            std::unique_ptr<LocationPath> m_path;
         };
 
     }
index bc8a1c3..fa37bd8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,8 +48,8 @@ Value Number::evaluate() const
     return m_value;
 }
 
-StringExpression::StringExpression(const String& value)
-    : m_value(value)
+StringExpression::StringExpression(String&& value)
+    : m_value(std::move(value))
 {
 }
 
@@ -58,26 +58,27 @@ Value StringExpression::evaluate() const
     return m_value;
 }
 
+Negative::Negative(std::unique_ptr<Expression> expression)
+{
+    addSubexpression(std::move(expression));
+}
+
 Value Negative::evaluate() const
 {
-    Value p(subExpression(0).evaluate());
-    return -p.toNumber();
+    return -subexpression(0).evaluate().toNumber();
 }
 
-NumericOp::NumericOp(Opcode opcode, Expression* lhs, Expression* rhs)
+NumericOp::NumericOp(Opcode opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
     : m_opcode(opcode)
 {
-    addSubExpression(lhs);
-    addSubExpression(rhs);
+    addSubexpression(std::move(lhs));
+    addSubexpression(std::move(rhs));
 }
 
 Value NumericOp::evaluate() const
 {
-    Value lhs(subExpression(0).evaluate());
-    Value rhs(subExpression(1).evaluate());
-    
-    double leftVal = lhs.toNumber();
-    double rightVal = rhs.toNumber();
+    double leftVal = subexpression(0).evaluate().toNumber();
+    double rightVal = subexpression(1).evaluate().toNumber();
 
     switch (m_opcode) {
         case OP_Add:
@@ -91,15 +92,16 @@ Value NumericOp::evaluate() const
         case OP_Mod:
             return fmod(leftVal, rightVal);
     }
+
     ASSERT_NOT_REACHED();
     return 0.0;
 }
 
-EqTestOp::EqTestOp(Opcode opcode, Expression* lhs, Expression* rhs)
+EqTestOp::EqTestOp(Opcode opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
     : m_opcode(opcode)
 {
-    addSubExpression(lhs);
-    addSubExpression(rhs);
+    addSubexpression(std::move(lhs));
+    addSubexpression(std::move(rhs));
 }
 
 bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
@@ -141,7 +143,7 @@ bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
             // the node-set to a boolean using the boolean function is true.
             return compare(lhs.toBoolean(), rhs);
         }
-        ASSERT(0);
+        ASSERT_NOT_REACHED();
     }
     if (rhs.isNodeSet()) {
         const NodeSet& rhsSet = rhs.toNodeSet();
@@ -159,7 +161,7 @@ bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
         }
         if (lhs.isBoolean())
             return compare(lhs, rhs.toBoolean());
-        ASSERT(0);
+        ASSERT_NOT_REACHED();
     }
     
     // Neither side is a NodeSet.
@@ -186,92 +188,87 @@ bool EqTestOp::compare(const Value& lhs, const Value& rhs) const
         case OP_LE:
             return lhs.toNumber() <= rhs.toNumber();
     }
-    ASSERT(0);
+
+    ASSERT_NOT_REACHED();
     return false;
 }
 
 Value EqTestOp::evaluate() const
 {
-    Value lhs(subExpression(0).evaluate());
-    Value rhs(subExpression(1).evaluate());
-
+    Value lhs(subexpression(0).evaluate());
+    Value rhs(subexpression(1).evaluate());
     return compare(lhs, rhs);
 }
 
-LogicalOp::LogicalOp(Opcode opcode, Expression* lhs, Expression* rhs)
+LogicalOp::LogicalOp(Opcode opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
     : m_opcode(opcode)
 {
-    addSubExpression(lhs);
-    addSubExpression(rhs);
+    addSubexpression(std::move(lhs));
+    addSubexpression(std::move(rhs));
 }
 
-bool LogicalOp::shortCircuitOn() const
+inline bool LogicalOp::shortCircuitOn() const
 {
-    if (m_opcode == OP_And)
-        return false; //false and foo
-
-    return true;  //true or bar
+    return m_opcode != OP_And;
 }
 
 Value LogicalOp::evaluate() const
 {
-    Value lhs(subExpression(0).evaluate());
-
     // This is not only an optimization, http://www.w3.org/TR/xpath
     // dictates that we must do short-circuit evaluation
-    bool lhsBool = lhs.toBoolean();
+    bool lhsBool = subexpression(0).evaluate().toBoolean();
     if (lhsBool == shortCircuitOn())
         return lhsBool;
 
-    return subExpression(1).evaluate().toBoolean();
+    return subexpression(1).evaluate().toBoolean();
+}
+
+Union::Union(std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs)
+{
+    addSubexpression(std::move(lhs));
+    addSubexpression(std::move(rhs));
 }
 
 Value Union::evaluate() const
 {
-    Value lhsResult = subExpression(0).evaluate();
-    Value rhs = subExpression(1).evaluate();
-    
+    Value lhsResult = subexpression(0).evaluate();
+    Value rhs = subexpression(1).evaluate();
+
     NodeSet& resultSet = lhsResult.modifiableNodeSet();
     const NodeSet& rhsNodes = rhs.toNodeSet();
-    
+
     HashSet<Node*> nodes;
     for (size_t i = 0; i < resultSet.size(); ++i)
         nodes.add(resultSet[i]);
-    
+
     for (size_t i = 0; i < rhsNodes.size(); ++i) {
         Node* node = rhsNodes[i];
         if (nodes.add(node).isNewEntry)
             resultSet.append(node);
     }
 
-    // It is also possible to use merge sort to avoid making the result unsorted;
-    // but this would waste the time in cases when order is not important.
+    // It would also be possible to perform a merge sort here to avoid making an unsorted result,
+    // but that would waste the time in cases when order is not important.
     resultSet.markSorted(false);
-    return lhsResult;
-}
 
-Predicate::Predicate(Expression* expr)
-    : m_expr(expr)
-{
-}
-
-Predicate::~Predicate()
-{
-    delete m_expr;
+    return lhsResult;
 }
 
-bool Predicate::evaluate() const
+bool evaluatePredicate(const Expression& expression)
 {
-    ASSERT(m_expr != 0);
-
-    Value result(m_expr->evaluate());
+    Value result(expression.evaluate());
 
     // foo[3] means foo[position()=3]
     if (result.isNumber())
-        return EqTestOp(EqTestOp::OP_EQ, createFunction("position"), new Number(result.toNumber())).evaluate().toBoolean();
+        return EqTestOp(EqTestOp::OP_EQ, Function::create(ASCIILiteral("position")), std::make_unique<Number>(result.toNumber())).evaluate().toBoolean();
 
     return result.toBoolean();
 }
 
+bool predicateIsContextPositionSensitive(const Expression& expression)
+{
+    return expression.isContextPositionSensitive() || expression.resultType() == Value::NumberValue;
+}
+
 }
 }
index 013ccda..542cc14 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,89 +34,87 @@ namespace WebCore {
 
     namespace XPath {
         
-        class Number : public Expression {
+        class Number FINAL : public Expression {
         public:
             explicit Number(double);
+
         private:
-            virtual Value evaluate() const;
-            virtual Value::Type resultType() const { return Value::NumberValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 
             Value m_value;
         };
 
-        class StringExpression : public Expression {
+        class StringExpression FINAL : public Expression {
         public:
-            explicit StringExpression(const String&);
+            explicit StringExpression(String&&);
+
         private:
-            virtual Value evaluate() const;
-            virtual Value::Type resultType() const { return Value::StringValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
 
             Value m_value;
         };
 
-        class Negative : public Expression {
+        class Negative FINAL : public Expression {
+        public:
+            explicit Negative(std::unique_ptr<Expression>);
+
         private:
-            virtual Value evaluate() const;
-            virtual Value::Type resultType() const { return Value::NumberValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
         };
 
-        class NumericOp : public Expression {
+        class NumericOp FINAL : public Expression {
         public:
-            enum Opcode {
-                OP_Add, OP_Sub, OP_Mul, OP_Div, OP_Mod
-            };
-            NumericOp(Opcode, Expression* lhs, Expression* rhs);
+            enum Opcode { OP_Add, OP_Sub, OP_Mul, OP_Div, OP_Mod };
+            NumericOp(Opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs);
+
         private:
-            virtual Value evaluate() const;
-            virtual Value::Type resultType() const { return Value::NumberValue; }
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
 
             Opcode m_opcode;
         };
 
-        class EqTestOp : public Expression {
+        class EqTestOp FINAL : public Expression {
         public:
             enum Opcode { OP_EQ, OP_NE, OP_GT, OP_LT, OP_GE, OP_LE };
-            EqTestOp(Opcode, Expression* lhs, Expression* rhs);
-            virtual Value evaluate() const;
+            EqTestOp(Opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs);
+            virtual Value evaluate() const OVERRIDE;
+
         private:
-            virtual Value::Type resultType() const { return Value::BooleanValue; }
+            virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
             bool compare(const Value&, const Value&) const;
 
             Opcode m_opcode;
         };
 
-        class LogicalOp : public Expression {
+        class LogicalOp FINAL : public Expression {
         public:
             enum Opcode { OP_And, OP_Or };
-            LogicalOp(Opcode, Expression* lhs, Expression* rhs);
+            LogicalOp(Opcode, std::unique_ptr<Expression> lhs, std::unique_ptr<Expression> rhs);
+
         private:
-            virtual Value::Type resultType() const { return Value::BooleanValue; }
+            virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
             bool shortCircuitOn() const;
-            virtual Value evaluate() const;
+            virtual Value evaluate() const OVERRIDE;
 
             Opcode m_opcode;
         };
 
-        class Union : public Expression {
-        private:
-            virtual Value evaluate() const;
-            virtual Value::Type resultType() const { return Value::NodeSetValue; }
-        };
-
-        class Predicate {
-            WTF_MAKE_NONCOPYABLE(Predicate); WTF_MAKE_FAST_ALLOCATED;
+        class Union FINAL : public Expression {
         public:
-            explicit Predicate(Expression*);
-            ~Predicate();
-            bool evaluate() const;
-
-            bool isContextPositionSensitive() const { return m_expr->isContextPositionSensitive() || m_expr->resultType() == Value::NumberValue; }
-            bool isContextSizeSensitive() const { return m_expr->isContextSizeSensitive(); }
+            Union(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
 
         private:
-            Expression* m_expr;
+            virtual Value evaluate() const OVERRIDE;
+            virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
         };
 
+        bool evaluatePredicate(const Expression&);
+        bool predicateIsContextPositionSensitive(const Expression&);
+
     }
 
 }
index 441dfe4..fe76179 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "Attr.h"
 #include "Document.h"
-#include "Element.h"
+#include "HTMLElement.h"
 #include "NodeTraversal.h"
 #include "XMLNSNames.h"
 #include "XPathParser.h"
 namespace WebCore {
 namespace XPath {
 
-Step::Step(Axis axis, const NodeTest& nodeTest, const Vector<Predicate*>& predicates)
+Step::Step(Axis axis, NodeTest nodeTest)
     : m_axis(axis)
-    , m_nodeTest(nodeTest)
-    , m_predicates(predicates)
+    , m_nodeTest(std::move(nodeTest))
+{
+}
+
+Step::Step(Axis axis, NodeTest nodeTest, Vector<std::unique_ptr<Expression>> predicates)
+    : m_axis(axis)
+    , m_nodeTest(std::move(nodeTest))
+    , m_predicates(std::move(predicates))
 {
 }
 
 Step::~Step()
 {
-    deleteAllValues(m_predicates);
-    deleteAllValues(m_nodeTest.mergedPredicates());
 }
 
 void Step::optimize()
@@ -57,59 +61,68 @@ void Step::optimize()
     // Evaluate predicates as part of node test if possible to avoid building unnecessary NodeSets.
     // E.g., there is no need to build a set of all "foo" nodes to evaluate "foo[@bar]", we can check the predicate while enumerating.
     // This optimization can be applied to predicates that are not context node list sensitive, or to first predicate that is only context position sensitive, e.g. foo[position() mod 2 = 0].
-    Vector<Predicate*> remainingPredicates;
+    Vector<std::unique_ptr<Expression>> remainingPredicates;
     for (size_t i = 0; i < m_predicates.size(); ++i) {
-        Predicate* predicate = m_predicates[i];
-        if ((!predicate->isContextPositionSensitive() || m_nodeTest.mergedPredicates().isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty()) {
-            m_nodeTest.mergedPredicates().append(predicate);
-        else
-            remainingPredicates.append(predicate);
+        auto& predicate = m_predicates[i];
+        if ((!predicateIsContextPositionSensitive(*predicate) || m_nodeTest.m_mergedPredicates.isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty())
+            m_nodeTest.m_mergedPredicates.append(std::move(predicate));
+        else
+            remainingPredicates.append(std::move(predicate));
     }
-    swap(remainingPredicates, m_predicates);
+    m_predicates = std::move(remainingPredicates);
 }
 
-void optimizeStepPair(Step* first, Step* second, bool& dropSecondStep)
+void optimizeStepPair(Step& first, Step& second, bool& dropSecondStep)
 {
     dropSecondStep = false;
 
-    if (first->m_axis == Step::DescendantOrSelfAxis
-        && first->m_nodeTest.kind() == Step::NodeTest::AnyNodeTest
-        && !first->m_predicates.size()
-        && !first->m_nodeTest.mergedPredicates().size()) {
-
-        ASSERT(first->m_nodeTest.data().isEmpty());
-        ASSERT(first->m_nodeTest.namespaceURI().isEmpty());
-
-        // Optimize the common case of "//" AKA /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest.
-        if (second->m_axis == Step::ChildAxis && second->predicatesAreContextListInsensitive()) {
-            first->m_axis = Step::DescendantAxis;
-            first->m_nodeTest = Step::NodeTest(second->m_nodeTest.kind(), second->m_nodeTest.data(), second->m_nodeTest.namespaceURI());
-            swap(second->m_nodeTest.mergedPredicates(), first->m_nodeTest.mergedPredicates());
-            swap(second->m_predicates, first->m_predicates);
-            first->optimize();
-            dropSecondStep = true;
-        }
-    }
+    if (first.m_axis != Step::DescendantOrSelfAxis)
+        return;
+
+    if (first.m_nodeTest.m_kind != Step::NodeTest::AnyNodeTest)
+        return;
+
+    if (!first.m_predicates.isEmpty())
+        return;
+
+    if (!first.m_nodeTest.m_mergedPredicates.isEmpty())
+        return;
+
+    ASSERT(first.m_nodeTest.m_data.isEmpty());
+    ASSERT(first.m_nodeTest.m_namespaceURI.isEmpty());
+
+    // Optimize the common case of "//" AKA /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest.
+    if (second.m_axis != Step::ChildAxis)
+        return;
+
+    if (!second.predicatesAreContextListInsensitive())
+        return;
+
+    first.m_axis = Step::DescendantAxis;
+    first.m_nodeTest = std::move(second.m_nodeTest);
+    first.m_predicates = std::move(second.m_predicates);
+    first.optimize();
+    dropSecondStep = true;
 }
 
 bool Step::predicatesAreContextListInsensitive() const
 {
     for (size_t i = 0; i < m_predicates.size(); ++i) {
-        Predicate* predicate = m_predicates[i];
-        if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive())
+        auto& predicate = *m_predicates[i];
+        if (predicateIsContextPositionSensitive(predicate) || predicate.isContextSizeSensitive())
             return false;
     }
 
-    for (size_t i = 0; i < m_nodeTest.mergedPredicates().size(); ++i) {
-        Predicate* predicate = m_nodeTest.mergedPredicates()[i];
-        if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive())
+    for (size_t i = 0; i < m_nodeTest.m_mergedPredicates.size(); ++i) {
+        auto& predicate = *m_nodeTest.m_mergedPredicates[i];
+        if (predicateIsContextPositionSensitive(predicate) || predicate.isContextSizeSensitive())
             return false;
     }
 
     return true;
 }
 
-void Step::evaluate(Node* context, NodeSet& nodes) const
+void Step::evaluate(Node& context, NodeSet& nodes) const
 {
     EvaluationContext& evaluationContext = Expression::evaluationContext();
     evaluationContext.position = 0;
@@ -118,7 +131,7 @@ void Step::evaluate(Node* context, NodeSet& nodes) const
 
     // Check predicates that couldn't be merged into node test.
     for (unsigned i = 0; i < m_predicates.size(); i++) {
-        Predicate* predicate = m_predicates[i];
+        auto& predicate = *m_predicates[i];
 
         NodeSet newNodes;
         if (!nodes.isSorted())
@@ -130,11 +143,11 @@ void Step::evaluate(Node* context, NodeSet& nodes) const
             evaluationContext.node = node;
             evaluationContext.size = nodes.size();
             evaluationContext.position = j + 1;
-            if (predicate->evaluate())
+            if (evaluatePredicate(predicate))
                 newNodes.append(node);
         }
 
-        nodes.swap(newNodes);
+        nodes = std::move(newNodes);
     }
 }
 
@@ -153,34 +166,34 @@ static inline Node::NodeType primaryNodeType(Step::Axis axis)
 #endif
 
 // Evaluate NodeTest without considering merged predicates.
-static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest)
+inline bool nodeMatchesBasicTest(Node& node, Step::Axis axis, const Step::NodeTest& nodeTest)
 {
-    switch (nodeTest.kind()) {
+    switch (nodeTest.m_kind) {
         case Step::NodeTest::TextNodeTest:
-            return node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE;
+            return node.nodeType() == Node::TEXT_NODE || node.nodeType() == Node::CDATA_SECTION_NODE;
         case Step::NodeTest::CommentNodeTest:
-            return node->nodeType() == Node::COMMENT_NODE;
+            return node.nodeType() == Node::COMMENT_NODE;
         case Step::NodeTest::ProcessingInstructionNodeTest: {
-            const AtomicString& name = nodeTest.data();
-            return node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node->nodeName() == name);
+            const AtomicString& name = nodeTest.m_data;
+            return node.nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node.nodeName() == name);
         }
         case Step::NodeTest::AnyNodeTest:
             return true;
         case Step::NodeTest::NameTest: {
-            const AtomicString& name = nodeTest.data();
-            const AtomicString& namespaceURI = nodeTest.namespaceURI();
+            const AtomicString& name = nodeTest.m_data;
+            const AtomicString& namespaceURI = nodeTest.m_namespaceURI;
 
             if (axis == Step::AttributeAxis) {
-                ASSERT(node->isAttributeNode());
+                ASSERT(node.isAttributeNode());
 
                 // In XPath land, namespace nodes are not accessible on the attribute axis.
-                if (node->namespaceURI() == XMLNSNames::xmlnsNamespaceURI)
+                if (node.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)
                     return false;
 
                 if (name == starAtom)
-                    return namespaceURI.isEmpty() || node->namespaceURI() == namespaceURI;
+                    return namespaceURI.isEmpty() || node.namespaceURI() == namespaceURI;
 
-                return node->localName() == name && node->namespaceURI() == namespaceURI;
+                return node.localName() == name && node.namespaceURI() == namespaceURI;
             }
 
             // Node test on the namespace axis is not implemented yet, the caller has a check for it.
@@ -188,28 +201,28 @@ static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step:
 
             // For other axes, the principal node type is element.
             ASSERT(primaryNodeType(axis) == Node::ELEMENT_NODE);
-            if (node->nodeType() != Node::ELEMENT_NODE)
+            if (!node.isElementNode())
                 return false;
 
             if (name == starAtom)
-                return namespaceURI.isEmpty() || namespaceURI == node->namespaceURI();
+                return namespaceURI.isEmpty() || namespaceURI == node.namespaceURI();
 
-            if (node->document().isHTMLDocument()) {
-                if (node->isHTMLElement()) {
+            if (node.document().isHTMLDocument()) {
+                if (node.isHTMLElement()) {
                     // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively.
-                    return equalIgnoringCase(toElement(node)->localName(), name) && (namespaceURI.isNull() || namespaceURI == node->namespaceURI());
+                    return equalIgnoringCase(toHTMLElement(node).localName(), name) && (namespaceURI.isNull() || namespaceURI == node.namespaceURI());
                 }
                 // An expression without any prefix shouldn't match no-namespace nodes (because HTML5 says so).
-                return toElement(node)->hasLocalName(name) && namespaceURI == node->namespaceURI() && !namespaceURI.isNull();
+                return toElement(node).hasLocalName(name) && namespaceURI == node.namespaceURI() && !namespaceURI.isNull();
             }
-            return toElement(node)->hasLocalName(name) && namespaceURI == node->namespaceURI();
+            return toElement(node).hasLocalName(name) && namespaceURI == node.namespaceURI();
         }
     }
     ASSERT_NOT_REACHED();
     return false;
 }
 
-static inline bool nodeMatches(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest)
+inline bool nodeMatches(Node& node, Step::Axis axis, const Step::NodeTest& nodeTest)
 {
     if (!nodeMatchesBasicTest(node, axis, nodeTest))
         return false;
@@ -219,13 +232,11 @@ static inline bool nodeMatches(Node* node, Step::Axis axis, const Step::NodeTest
     // Only the first merged predicate may depend on position.
     ++evaluationContext.position;
 
-    const Vector<Predicate*>& mergedPredicates = nodeTest.mergedPredicates();
+    auto& mergedPredicates = nodeTest.m_mergedPredicates;
     for (unsigned i = 0; i < mergedPredicates.size(); i++) {
-        Predicate* predicate = mergedPredicates[i];
-
-        evaluationContext.node = node;
         // No need to set context size - we only get here when evaluating predicates that do not depend on it.
-        if (!predicate->evaluate())
+        evaluationContext.node = &node;
+        if (!evaluatePredicate(*mergedPredicates[i]))
             return false;
     }
 
@@ -233,124 +244,126 @@ static inline bool nodeMatches(Node* node, Step::Axis axis, const Step::NodeTest
 }
 
 // Result nodes are ordered in axis order. Node test (including merged predicates) is applied.
-void Step::nodesInAxis(Node* context, NodeSet& nodes) const
+void Step::nodesInAxis(Node& context, NodeSet& nodes) const
 {
     ASSERT(nodes.isEmpty());
     switch (m_axis) {
         case ChildAxis:
-            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
+            if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
                 return;
-
-            for (Node* n = context->firstChild(); n; n = n->nextSibling())
-                if (nodeMatches(n, ChildAxis, m_nodeTest))
-                    nodes.append(n);
+            for (Node* node = context.firstChild(); node; node = node->nextSibling()) {
+                if (nodeMatches(*node, ChildAxis, m_nodeTest))
+                    nodes.append(node);
+            }
             return;
         case DescendantAxis:
-            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
+            if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
                 return;
-
-            for (Node* n = context->firstChild(); n; n = NodeTraversal::next(n, context))
-                if (nodeMatches(n, DescendantAxis, m_nodeTest))
-                    nodes.append(n);
+            for (Node* node = context.firstChild(); node; node = NodeTraversal::next(node, &context)) {
+                if (nodeMatches(*node, DescendantAxis, m_nodeTest))
+                    nodes.append(node);
+            }
             return;
         case ParentAxis:
-            if (context->isAttributeNode()) {
-                Element* n = static_cast<Attr*>(context)->ownerElement();
-                if (nodeMatches(n, ParentAxis, m_nodeTest))
-                    nodes.append(n);
+            if (context.isAttributeNode()) {
+                Element* node = static_cast<Attr&>(context).ownerElement();
+                if (nodeMatches(*node, ParentAxis, m_nodeTest))
+                    nodes.append(node);
             } else {
-                ContainerNode* n = context->parentNode();
-                if (n && nodeMatches(n, ParentAxis, m_nodeTest))
-                    nodes.append(n);
+                ContainerNode* node = context.parentNode();
+                if (node && nodeMatches(*node, ParentAxis, m_nodeTest))
+                    nodes.append(node);
             }
             return;
         case AncestorAxis: {
-            Node* n = context;
-            if (context->isAttributeNode()) {
-                n = static_cast<Attr*>(context)->ownerElement();
-                if (nodeMatches(n, AncestorAxis, m_nodeTest))
-                    nodes.append(n);
+            Node* node = &context;
+            if (context.isAttributeNode()) {
+                node = static_cast<Attr&>(context).ownerElement();
+                if (nodeMatches(*node, AncestorAxis, m_nodeTest))
+                    nodes.append(node);
+            }
+            for (node = node->parentNode(); node; node = node->parentNode()) {
+                if (nodeMatches(*node, AncestorAxis, m_nodeTest))
+                    nodes.append(node);
             }
-            for (n = n->parentNode(); n; n = n->parentNode())
-                if (nodeMatches(n, AncestorAxis, m_nodeTest))
-                    nodes.append(n);
             nodes.markSorted(false);
             return;
         }
         case FollowingSiblingAxis:
-            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
-                 context->nodeType() == Node::XPATH_NAMESPACE_NODE) 
+            if (context.nodeType() == Node::ATTRIBUTE_NODE || context.nodeType() == Node::XPATH_NAMESPACE_NODE)
                 return;
-            
-            for (Node* n = context->nextSibling(); n; n = n->nextSibling())
-                if (nodeMatches(n, FollowingSiblingAxis, m_nodeTest))
-                    nodes.append(n);
+            for (Node* node = context.nextSibling(); node; node = node->nextSibling()) {
+                if (nodeMatches(*node, FollowingSiblingAxis, m_nodeTest))
+                    nodes.append(node);
+            }
             return;
         case PrecedingSiblingAxis:
-            if (context->nodeType() == Node::ATTRIBUTE_NODE ||
-                 context->nodeType() == Node::XPATH_NAMESPACE_NODE)
+            if (context.nodeType() == Node::ATTRIBUTE_NODE || context.nodeType() == Node::XPATH_NAMESPACE_NODE)
                 return;
-            
-            for (Node* n = context->previousSibling(); n; n = n->previousSibling())
-                if (nodeMatches(n, PrecedingSiblingAxis, m_nodeTest))
-                    nodes.append(n);
-
+            for (Node* node = context.previousSibling(); node; node = node->previousSibling()) {
+                if (nodeMatches(*node, PrecedingSiblingAxis, m_nodeTest))
+                    nodes.append(node);
+            }
             nodes.markSorted(false);
             return;
         case FollowingAxis:
-            if (context->isAttributeNode()) {
-                Node* p = static_cast<Attr*>(context)->ownerElement();
-                while ((p = NodeTraversal::next(p)))
-                    if (nodeMatches(p, FollowingAxis, m_nodeTest))
-                        nodes.append(p);
+            if (context.isAttributeNode()) {
+                Node* node = static_cast<Attr&>(context).ownerElement();
+                while ((node = NodeTraversal::next(node))) {
+                    if (nodeMatches(*node, FollowingAxis, m_nodeTest))
+                        nodes.append(node);
+                }
             } else {
-                for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
-                    for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
-                        if (nodeMatches(n, FollowingAxis, m_nodeTest))
-                            nodes.append(n);
-                        for (Node* c = n->firstChild(); c; c = NodeTraversal::next(c, n))
-                            if (nodeMatches(c, FollowingAxis, m_nodeTest))
-                                nodes.append(c);
+                for (Node* parent = &context; !isRootDomNode(parent); parent = parent->parentNode()) {
+                    for (Node* node = parent->nextSibling(); node; node = node->nextSibling()) {
+                        if (nodeMatches(*node, FollowingAxis, m_nodeTest))
+                            nodes.append(node);
+                        for (Node* child = node->firstChild(); child; child = NodeTraversal::next(child, node)) {
+                            if (nodeMatches(*child, FollowingAxis, m_nodeTest))
+                                nodes.append(child);
+                        }
                     }
                 }
             }
             return;
         case PrecedingAxis: {
-            if (context->isAttributeNode())
-                context = static_cast<Attr*>(context)->ownerElement();
-
-            Node* n = context;
-            while (ContainerNode* parent = n->parentNode()) {
-                for (n = NodeTraversal::previous(n); n != parent; n = NodeTraversal::previous(n))
-                    if (nodeMatches(n, PrecedingAxis, m_nodeTest))
-                        nodes.append(n);
-                n = parent;
+            Node* node;
+            if (context.isAttributeNode())
+                node = static_cast<Attr&>(context).ownerElement();
+            else
+                node = &context;
+            while (ContainerNode* parent = node->parentNode()) {
+                for (node = NodeTraversal::previous(node); node != parent; node = NodeTraversal::previous(node)) {
+                    if (nodeMatches(*node, PrecedingAxis, m_nodeTest))
+                        nodes.append(node);
+                }
+                node = parent;
             }
             nodes.markSorted(false);
             return;
         }
         case AttributeAxis: {
-            if (!context->isElementNode())
+            if (!context.isElementNode())
                 return;
 
-            Element* contextElement = toElement(context);
+            Element& contextElement = toElement(context);
 
             // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
-            if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) {
-                RefPtr<Node> n = contextElement->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data());
-                if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
-                    if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
-                        nodes.append(n.release());
+            if (m_nodeTest.m_kind == NodeTest::NameTest && m_nodeTest.m_data != starAtom) {
+                RefPtr<Attr> attr = contextElement.getAttributeNodeNS(m_nodeTest.m_namespaceURI, m_nodeTest.m_data);
+                if (attr && attr->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
+                    if (nodeMatches(*attr, AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
+                        nodes.append(attr.release());
                 }
                 return;
             }
             
-            if (!contextElement->hasAttributes())
+            if (!contextElement.hasAttributes())
                 return;
 
-            for (unsigned i = 0; i < contextElement->attributeCount(); ++i) {
-                RefPtr<Attr> attr = contextElement->ensureAttr(contextElement->attributeAt(i).name());
-                if (nodeMatches(attr.get(), AttributeAxis, m_nodeTest))
+            for (unsigned i = 0; i < contextElement.attributeCount(); ++i) {
+                RefPtr<Attr> attr = contextElement.ensureAttr(contextElement.attributeAt(i).name());
+                if (nodeMatches(*attr, AttributeAxis, m_nodeTest))
                     nodes.append(attr.release());
             }
             return;
@@ -360,31 +373,31 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const
             return;
         case SelfAxis:
             if (nodeMatches(context, SelfAxis, m_nodeTest))
-                nodes.append(context);
+                nodes.append(&context);
             return;
         case DescendantOrSelfAxis:
             if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest))
-                nodes.append(context);
-            if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children.
+                nodes.append(&context);
+            if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
                 return;
-
-            for (Node* n = context->firstChild(); n; n = NodeTraversal::next(n, context))
-            if (nodeMatches(n, DescendantOrSelfAxis, m_nodeTest))
-                nodes.append(n);
+            for (Node* node = context.firstChild(); node; node = NodeTraversal::next(node, &context)) {
+                if (nodeMatches(*node, DescendantOrSelfAxis, m_nodeTest))
+                    nodes.append(node);
+            }
             return;
         case AncestorOrSelfAxis: {
             if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest))
-                nodes.append(context);
-            Node* n = context;
-            if (context->isAttributeNode()) {
-                n = static_cast<Attr*>(context)->ownerElement();
-                if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest))
-                    nodes.append(n);
+                nodes.append(&context);
+            Node* node = &context;
+            if (context.isAttributeNode()) {
+                node = static_cast<Attr&>(context).ownerElement();
+                if (nodeMatches(*node, AncestorOrSelfAxis, m_nodeTest))
+                    nodes.append(node);
+            }
+            for (node = node->parentNode(); node; node = node->parentNode()) {
+                if (nodeMatches(*node, AncestorOrSelfAxis, m_nodeTest))
+                    nodes.append(node);
             }
-            for (n = n->parentNode(); n; n = n->parentNode())
-                if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest))
-                    nodes.append(n);
-
             nodes.markSorted(false);
             return;
         }
@@ -392,6 +405,5 @@ void Step::nodesInAxis(Node* context, NodeSet& nodes) const
     ASSERT_NOT_REACHED();
 }
 
-
 }
 }
index f678f92..d928357 100644 (file)
@@ -27,8 +27,8 @@
 #ifndef XPathStep_h
 #define XPathStep_h
 
-#include "XPathExpressionNode.h"
-#include "XPathNodeSet.h"
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
 
 namespace WebCore {
 
@@ -36,10 +36,10 @@ class Node;
 
 namespace XPath {
 
-class Predicate;
-        
-class Step : public ParseNode {
-    WTF_MAKE_NONCOPYABLE(Step);
+class Expression;
+class NodeSet;
+
+class Step {
     WTF_MAKE_FAST_ALLOCATED;
 public:
     enum Axis {
@@ -49,57 +49,73 @@ public:
         ParentAxis, PrecedingAxis, PrecedingSiblingAxis,
         SelfAxis
     };
-           
+
     class NodeTest {
         WTF_MAKE_FAST_ALLOCATED;
     public:
-        enum Kind {
-            TextNodeTest, CommentNodeTest, ProcessingInstructionNodeTest, AnyNodeTest, NameTest
-        };
-
-        NodeTest(Kind kind) : m_kind(kind) { }
-        NodeTest(Kind kind, const String& data) : m_kind(kind), m_data(data) { }
-        NodeTest(Kind kind, const String& data, const String& namespaceURI) : m_kind(kind), m_data(data), m_namespaceURI(namespaceURI) { }
-                
-        Kind kind() const { return m_kind; }
-        const AtomicString& data() const { return m_data; }
-        const AtomicString& namespaceURI() const { return m_namespaceURI; }
-        Vector<Predicate*>& mergedPredicates() { return m_mergedPredicates; }
-        const Vector<Predicate*>& mergedPredicates() const { return m_mergedPredicates; }
-                
+        enum Kind { TextNodeTest, CommentNodeTest, ProcessingInstructionNodeTest, AnyNodeTest, NameTest };
+
+        explicit NodeTest(Kind kind) : m_kind(kind) { }
+        NodeTest(Kind kind, const AtomicString& data) : m_kind(kind), m_data(data) { }
+        NodeTest(Kind kind, const AtomicString& data, const AtomicString& namespaceURI) : m_kind(kind), m_data(data), m_namespaceURI(namespaceURI) { }
+
+#if COMPILER(MSVC)
+        NodeTest(const NodeTest&);
+        void operator=(const NodeTest&);
+
+        NodeTest(NodeTest&& other)
+            : m_kind(other.m_kind)
+            , m_data(std::move(other.m_data))
+            , m_namespaceURI(std::move(other.m_namespaceURI))
+            , m_mergedPredicates(std::move(m_mergedPredicates))
+        {
+        }
+        NodeTest& operator=(NodeTest&& other)
+        {
+            m_kind = other.m_kind;
+            m_data = std::move(other.m_data);
+            m_namespaceURI = std::move(other.m_namespaceURI);
+            m_mergedPredicates = std::move(m_mergedPredicates);
+            return *this;
+        }
+#endif
+
     private:
+        friend class Step;
+        friend void optimizeStepPair(Step&, Step&, bool&);
+        friend bool nodeMatchesBasicTest(Node&, Axis, const NodeTest&);
+        friend bool nodeMatches(Node&, Axis, const NodeTest&);
+
         Kind m_kind;
         AtomicString m_data;
         AtomicString m_namespaceURI;
-
-        // When possible, we merge some or all predicates with node test for better performance.
-        Vector<Predicate*> m_mergedPredicates;
+        Vector<std::unique_ptr<Expression>> m_mergedPredicates;
     };
 
-    Step(Axis, const NodeTest&, const Vector<Predicate*>& predicates = Vector<Predicate*>());
+    Step(Axis, NodeTest);
+    Step(Axis, NodeTest, Vector<std::unique_ptr<Expression>>);
     ~Step();
 
     void optimize();
 
-    void evaluate(Node* context, NodeSet&) const;
+    void evaluate(Node& context, NodeSet&) const;
 
     Axis axis() const { return m_axis; }
-    const NodeTest& nodeTest() const { return m_nodeTest; }
 
 private:
-    friend void optimizeStepPair(Step*, Step*, bool&);
+    friend void optimizeStepPair(Step&, Step&, bool&);
+
     bool predicatesAreContextListInsensitive() const;
 
     void parseNodeTest(const String&);
-    void nodesInAxis(Node* context, NodeSet&) const;
-    String namespaceFromNodetest(const String& nodeTest) const;
+    void nodesInAxis(Node& context, NodeSet&) const;
 
     Axis m_axis;
     NodeTest m_nodeTest;
-    Vector<Predicate*> m_predicates;
+    Vector<std::unique_ptr<Expression>> m_predicates;
 };
 
-void optimizeStepPair(Step*, Step*, bool& dropSecondStep);
+void optimizeStepPair(Step&, Step&, bool& dropSecondStep);
 
 } // namespace XPath
 
index 8cbc7a6..8d3cba7 100644 (file)
@@ -50,7 +50,7 @@ String stringValue(Node* node)
         case Node::XPATH_NAMESPACE_NODE:
             return node->nodeValue();
         default:
-            if (isRootDomNode(node) || node->nodeType() == Node::ELEMENT_NODE)
+            if (isRootDomNode(node) || node->isElementNode())
                 return TextNodeTraversal::contentsAsString(node);
     }
     return String();
index ed43f48..2bd0398 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "XPathUtil.h"
 #include <limits>
 #include <wtf/MathExtras.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
 
-using std::numeric_limits;
-
 namespace WebCore {
 namespace XPath {
 
-const Value::AdoptTag Value::adopt = {};
-
 const NodeSet& Value::toNodeSet() const
 {
     if (!isNodeSet())
         Expression::evaluationContext().hadTypeConversionError = true;
 
     if (!m_data) {
-        DEFINE_STATIC_LOCAL(NodeSet, emptyNodeSet, ());
+        static NeverDestroyed<NodeSet> emptyNodeSet;
         return emptyNodeSet;
     }
 
-    return m_data->m_nodeSet;
+    return m_data->nodeSet;
 }    
 
 NodeSet& Value::modifiableNodeSet()
@@ -60,23 +57,23 @@ NodeSet& Value::modifiableNodeSet()
         Expression::evaluationContext().hadTypeConversionError = true;
 
     if (!m_data)
-        m_data = ValueData::create();
-    
+        m_data = Data::create();
+
     m_type = NodeSetValue;
-    return m_data->m_nodeSet;
+    return m_data->nodeSet;
 }
 
 bool Value::toBoolean() const
 {
     switch (m_type) {
         case NodeSetValue:
-            return !m_data->m_nodeSet.isEmpty();
+            return !m_data->nodeSet.isEmpty();
         case BooleanValue:
             return m_bool;
         case NumberValue:
             return m_number && !std::isnan(m_number);
         case StringValue:
-            return !m_data->m_string.isEmpty();
+            return !m_data->string.isEmpty();
     }
     ASSERT_NOT_REACHED();
     return false;
@@ -90,25 +87,26 @@ double Value::toNumber() const
         case NumberValue:
             return m_number;
         case StringValue: {
-            const String& str = m_data->m_string.simplifyWhiteSpace();
+            const String& str = m_data->string.simplifyWhiteSpace();
 
             // String::toDouble() supports exponential notation, which is not allowed in XPath.
             unsigned len = str.length();
             for (unsigned i = 0; i < len; ++i) {
                 UChar c = str[i];
                 if (!isASCIIDigit(c) && c != '.'  && c != '-')
-                    return numeric_limits<double>::quiet_NaN();
+                    return std::numeric_limits<double>::quiet_NaN();
             }
 
             bool canConvert;
             double value = str.toDouble(&canConvert);
             if (canConvert)
                 return value;
-            return numeric_limits<double>::quiet_NaN();
+            return std::numeric_limits<double>::quiet_NaN();
         }
         case BooleanValue:
             return m_bool;
     }
+
     ASSERT_NOT_REACHED();
     return 0.0;
 }
@@ -117,22 +115,23 @@ String Value::toString() const
 {
     switch (m_type) {
         case NodeSetValue:
-            if (m_data->m_nodeSet.isEmpty()) 
-                return "";
-            return stringValue(m_data->m_nodeSet.firstNode());
+            if (m_data->nodeSet.isEmpty())
+                return emptyString();
+            return stringValue(m_data->nodeSet.firstNode());
         case StringValue:
-            return m_data->m_string;
+            return m_data->string;
         case NumberValue:
             if (std::isnan(m_number))
-                return "NaN";
+                return ASCIILiteral("NaN");
             if (m_number == 0)
-                return "0";
+                return ASCIILiteral("0");
             if (std::isinf(m_number))
-                return std::signbit(m_number) ? "-Infinity" : "Infinity";
+                return ASCIILiteral(std::signbit(m_number) ? "-Infinity" : "Infinity");
             return String::number(m_number);
         case BooleanValue:
-            return m_bool ? "true" : "false";
+            return ASCIILiteral(m_bool ? "true" : "false");
     }
+
     ASSERT_NOT_REACHED();
     return String();
 }
index 490bb2d..1deec33 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2005 Frerich Raabe <raabe@kde.org>
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #define XPathValue_h
 
 #include "XPathNodeSet.h"
-#include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
     namespace XPath {
     
-        class ValueData : public RefCounted<ValueData> {
-        public:            
-            static PassRefPtr<ValueData> create() { return adoptRef(new ValueData); }
-            static PassRefPtr<ValueData> create(const NodeSet& nodeSet) { return adoptRef(new ValueData(nodeSet)); }
-            static PassRefPtr<ValueData> create(const String& string) { return adoptRef(new ValueData(string)); }
-
-            NodeSet m_nodeSet;
-            String m_string;
-            
-        private:
-            ValueData() { }
-            explicit ValueData(const NodeSet& nodeSet) : m_nodeSet(nodeSet) { }
-            explicit ValueData(const String& string) : m_string(string) { }            
-        };
-
-        // Copying Value objects makes their data partially shared, so care has to be taken when dealing with copies.
         class Value {
         public:
             enum Type { NodeSetValue, BooleanValue, NumberValue, StringValue };
             
-            Value(unsigned value) : m_type(NumberValue), m_bool(false), m_number(value) {}
-            Value(unsigned long value) : m_type(NumberValue), m_bool(false), m_number(value) {}
-            Value(double value) : m_type(NumberValue), m_bool(false), m_number(value) {}
-
-            Value(const char* value) : m_type(StringValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
-            Value(const String& value) : m_type(StringValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
-            Value(const NodeSet& value) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create(value)) {}
-            Value(Node* value) : m_type(NodeSetValue), m_bool(false), m_number(0), m_data(ValueData::create()) { m_data->m_nodeSet.append(value); }
+            Value(bool value) : m_type(BooleanValue), m_bool(value) { }
+            Value(unsigned value) : m_type(NumberValue), m_number(value) { }
+            Value(double value) : m_type(NumberValue), m_number(value) { }
 
-            // This is needed to safely implement constructing from bool - with normal function overloading, any pointer type would match.
-            template<typename T> Value(T);
+            Value(const String& value) : m_type(StringValue), m_data(Data::create(value)) { }
+            Value(const char* value) : m_type(StringValue), m_data(Data::create(value)) { }
 
-            static const struct AdoptTag {} adopt;
-            Value(NodeSet& value, const AdoptTag&) : m_type(NodeSetValue), m_bool(false), m_number(0),  m_data(ValueData::create()) { value.swap(m_data->m_nodeSet); }
+            explicit Value(NodeSet value) : m_type(NodeSetValue), m_data(Data::create(std::move(value))) { }
+            explicit Value(Node* value) : m_type(NodeSetValue), m_data(Data::create(value)) { }
+            explicit Value(PassRefPtr<Node> value) : m_type(NodeSetValue), m_data(Data::create(value)) { }
 
             Type type() const { return m_type; }
 
@@ -77,25 +56,39 @@ namespace WebCore {
             bool isString() const { return m_type == StringValue; }
 
             const NodeSet& toNodeSet() const;
-            NodeSet& modifiableNodeSet();
             bool toBoolean() const;
             double toNumber() const;
             String toString() const;
 
+            // Note that the NodeSet is shared with other Values that this one was copied from or that are copies of this one.
+            NodeSet& modifiableNodeSet();
+
         private:
+            // This constructor creates ambiguity so that we don't accidentally call the boolean overload for pointer types.
+            Value(void*) WTF_DELETED_FUNCTION;
+
+            struct Data : public RefCounted<Data> {
+                static PassRefPtr<Data> create() { return adoptRef(new Data); }
+                static PassRefPtr<Data> create(const String& string) { return adoptRef(new Data(string)); }
+                static PassRefPtr<Data> create(NodeSet nodeSet) { return adoptRef(new Data(std::move(nodeSet))); }
+                static PassRefPtr<Data> create(PassRefPtr<Node> node) { return adoptRef(new Data(node)); }
+
+                String string;
+                NodeSet nodeSet;
+
+            private:
+                Data() { }
+                explicit Data(const String& string) : string(string) { }
+                explicit Data(NodeSet nodeSet) : nodeSet(std::move(nodeSet)) { }
+                explicit Data(PassRefPtr<Node> node) : nodeSet(node) { }
+            };
+
             Type m_type;
             bool m_bool;
             double m_number;
-            RefPtr<ValueData> m_data;
+            RefPtr<Data> m_data;
         };
 
-        template<>
-        inline Value::Value(bool value)
-            : m_type(BooleanValue)
-            , m_bool(value)
-            , m_number(0)
-        {
-        }
     }
 }