LCOV - code coverage report
Current view: top level - snapwebsites - qdomxpath.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 3076 0.1 %
Date: 2019-12-15 17:13:15 Functions: 2 278 0.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Servers -- retrieve a list of nodes from a QDomDocument based on an XPath
       2             : // Copyright (c) 2013-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : 
      19             : // self
      20             : //
      21             : #include "snapwebsites/qdomxpath.h"
      22             : 
      23             : 
      24             : // snapwebsites lib
      25             : //
      26             : #include "snapwebsites/floats.h"
      27             : #include "snapwebsites/qstring_stream.h"
      28             : 
      29             : 
      30             : // snapdev lib
      31             : //
      32             : #include <snapdev/not_used.h>
      33             : 
      34             : 
      35             : // C++ lib
      36             : //
      37             : #include <cmath>
      38             : #include <iomanip>
      39             : #include <limits>
      40             : 
      41             : 
      42             : // last include
      43             : //
      44             : #include <snapdev/poison.h>
      45             : 
      46             : 
      47             : 
      48             : const char *                    QDomXPath::MAGIC = "XPTH";
      49             : const QDomXPath::instruction_t  QDomXPath::VERSION_MAJOR;
      50             : const QDomXPath::instruction_t  QDomXPath::VERSION_MINOR;
      51             : 
      52             : 
      53             : 
      54             : /** \brief Verification mode.
      55             :  *
      56             :  * If the QDOM_XPATH_VERIFICATION macro is set to zero (0) then no
      57             :  * verifications are used while executing a program. Assuming that we
      58             :  * ironed out all the bugs, this is as safe as with the verifications,
      59             :  * only faster since we can skip of all the checks.
      60             :  *
      61             :  * This flag is mainly for debug purposes to ensure that our tables
      62             :  * are properly defined as one make use of positioned pointers and
      63             :  * such need to be 100% correct for the execution environment to
      64             :  * work as expected.
      65             :  */
      66             : #define QDOM_XPATH_VERIFICATION     1
      67             : 
      68             : 
      69             : /** \file
      70             :  * \brief The DOM XPath Compiler transforms an XPath to bytecode.
      71             :  *
      72             :  * The bytecode is a very simple set of commands, each defined as one byte.
      73             :  * Only the PUSH and BRANCH instructions use additional bytes to allow for
      74             :  * immediate data to be used to get everything to work as expected.
      75             :  *
      76             :  * The idea of using a compiler allows us to avoid having to recompile the
      77             :  * XPath each time (very often) we use it. Overall, it is a lot of time
      78             :  * saved (if we were to run the XPath expression only once, it would be
      79             :  * a big waste, but if you run it 1 million times a day, that's quite a
      80             :  * saving.
      81             :  *
      82             :  * The process requires a lot of DOM calls and thus creating a C++ program,
      83             :  * instead of a simple bytecode would require hundreds of lines of code and
      84             :  * the result would probably not be any better than the bytecode because it
      85             :  * would not use much of the CPU code cache.
      86             :  *
      87             :  * The main process when executing an XPath is a loop over a set of nodes
      88             :  * related to what is currently the context node. Each node becomes the
      89             :  * context node in turn and gets checked against the following set of
      90             :  * predicates.
      91             :  *
      92             :  * The following represents one entry in an XPath:
      93             :  *
      94             :  * \code
      95             :  * // Note that although everything is optional, you should probably have
      96             :  * // at least one entry (i.e. "." or maybe "[@color='pink']") although
      97             :  * // the empty xpath is accepted but it returns an empty set of nodes...
      98             :  * [ '/' [ '/' ] ] [ <axis> '::' ] [ <prefix> ':' ] [ <tagname> ] ( '[' <predicate> ']' )*
      99             :  * \endcode
     100             :  *
     101             :  * Each entry is separated by a slash when there are several. If the XPath
     102             :  * starts with one or two slashes then the context node is set to the root.
     103             :  * Otherwise it is a relative path and the current node is chosen.
     104             :  *
     105             :  * By default the \<axis> is 'child::node()/' meaning that children of the
     106             :  * context node become the elements of the list we're working on. Note that
     107             :  * attributes of a node are somewhat considered as being children, but
     108             :  * they can only be accessed with the 'attribute' axis (which can be
     109             :  * abbreviated with '@'.) The double slash syntax is an equivalent to
     110             :  * the "descendant-or-self::node()/" axis.
     111             :  *
     112             :  * The axis defines the list of nodes and in theory all those nodes are
     113             :  * put in a list. However, in practice this is not wise since the list
     114             :  * can be quite big. However, many axis represent a large list of nodes
     115             :  * (possibly all the nodes in the document being worked on) and in that
     116             :  * case premature application of the tag name predicate would be incorrect.
     117             :  * For example, "/descendant::p" can be used to retrieve all the \<p> tag
     118             :  * of an HTML document. If we were to test the tag name early, then the
     119             :  * process would stop at the \<html> or \<body> tags and not find any
     120             :  * \<p> tag at all. The algorithms we use take that in account.
     121             :  *
     122             :  * Note that \<tagname> is mandatory in an entry, however, it can be set to
     123             :  * '*' to match all the nodes that the axis defines.
     124             :  *
     125             :  * The reason why we need to get all the nodes (at least in theory) is
     126             :  * because functions such as position(), last(), and count() require the
     127             :  * right information and that means a correct list (no possible optimization
     128             :  * there!) However, those functions cannot get applied before the predicates
     129             :  * written between square brackets ('[' and ']'). This means the gathering of
     130             :  * the list of nodes can make use of the axis, prefix, and tag name.
     131             :  *
     132             :  * Once we have a list of nodes, we can apply the predicates against that
     133             :  * list. This is done with a for() loop and an index (this is important to
     134             :  * get the right value for the position() command.) Since a predicate can
     135             :  * itself include an XPath, the process is repeated there to compute the
     136             :  * predicate. The current state is therefore saved and a new state created
     137             :  * to manage the predicate. Once the predicate returns, the result is a
     138             :  * Boolean. If true, that node is added to the result. If false, the node
     139             :  * is ignored.
     140             :  *
     141             :  * The axis is the function that determines what is to be read from the DOM.
     142             :  * The prefix and the tag name are the preliminary predicates that can be
     143             :  * applied as the DOM is being scanned.
     144             :  *
     145             :  * \code
     146             :  * setup state with input node(s) as the list of nodes in that state
     147             :  * for each union
     148             :  *   create a child state as a clone of the original input state
     149             :  *   for each entry
     150             :  *     if current state node-set is empty, exit loop
     151             :  *     mark entry as current
     152             :  *     for each node in the current state
     153             :  *       (as nodes are selected they become the current context node)
     154             :  *       create a child state
     155             :  *       run the current selection against the current state and save the nodes in the child state
     156             :  *       for each node in the child state
     157             :  *         for each predicate
     158             :  *           calculate the predicate
     159             :  *           if the predicate returned true
     160             :  *               or the predicate returned a number and position() == number
     161             :  *               or the predicate returned a non-empty list of nodes [TBD]
     162             :  *             save the node in the result
     163             :  *           endif
     164             :  *         loop
     165             :  *       loop
     166             :  *     loop
     167             :  *     add the child state result to the current state result
     168             :  *   loop
     169             :  *   add the child state result to the current state result
     170             :  * loop
     171             :  * \endcode
     172             :  *
     173             :  * The UnionExpr expression becomes the outter most loop. That loop may
     174             :  * be removed if no union actually exists (no | was used between two
     175             :  * paths.)
     176             :  *
     177             :  * Note that several of the "for each" loops are actually unfolded in
     178             :  * the program because each loop iteration has completely different things
     179             :  * to work on. Here are simplied examples of the UnionExpr and the
     180             :  * PathExpr.
     181             :  *
     182             :  * \code
     183             :  * // Main Program
     184             :  * setup original state
     185             :  * call UnionExpr 1
     186             :  * return
     187             :  *
     188             :  * // UnionExpr
     189             :  * create clone of original state, make the clone current
     190             :  * call PathExpr 1
     191             :  * add current state result to original state
     192             :  * call PathExpr 2
     193             :  * add current state result to original state
     194             :  * call PathExpr 3
     195             :  * add current state result to original state
     196             :  * ...
     197             :  * return
     198             :  *
     199             :  * // PathExpr 1
     200             :  * create an empty child state
     201             :  * apply Entry 1 computing a node-set
     202             :  * for each node in child state
     203             :  *   call Predicate 1.1
     204             :  * loop
     205             :  * if child state result is empty, return
     206             :  * replace child state node-set with result node-set
     207             :  * for each node in child state
     208             :  *   call Predicate 1.2
     209             :  * loop
     210             :  * if child state result is empty, return
     211             :  * replace child state node-set with result node-set
     212             :  * for each node in child state
     213             :  *   call Predicate 1.3
     214             :  * loop
     215             :  * if current state result is empty, return
     216             :  * replace child state node-set with result node-set
     217             :  * ...
     218             :  *
     219             :  * apply Entry 2 computing a node-set
     220             :  * for each node in child state
     221             :  *   call Predicate 2.1
     222             :  * loop
     223             :  * if child state result is empty, return
     224             :  * replace child state node-set with result node-set
     225             :  * for each node in child state
     226             :  *   call Predicate 2.2
     227             :  * loop
     228             :  * if child state result is empty, return
     229             :  * replace child state node-set with result node-set
     230             :  * for each node in child state
     231             :  *   call Predicate 2.3
     232             :  * loop
     233             :  * if current state result is empty, return
     234             :  * replace child state node-set with result node-set
     235             :  * ...
     236             :  *
     237             :  * apply Entry 3 computing a node-set
     238             :  * for each node in child state
     239             :  *   call Predicate 3.1
     240             :  * loop
     241             :  * if child state result is empty, return
     242             :  * replace child state node-set with result node-set
     243             :  * for each node in child state
     244             :  *   call Predicate 3.2
     245             :  * loop
     246             :  * if child state result is empty, return
     247             :  * replace child state node-set with result node-set
     248             :  * for each node in child state
     249             :  *   call Predicate 3.3
     250             :  * loop
     251             :  * if current state result is empty, return
     252             :  * replace child state node-set with result node-set
     253             :  * ...
     254             :  *
     255             :  * return
     256             :  *
     257             :  * \endcode
     258             :  *
     259             :  * \code
     260             :  * ...
     261             :  * create an empty child state + apply Entry 1 computing a node-set (i.e. axis)
     262             :  * if child node-set is empty, return
     263             :  * set current node position to 1
     264             :  * label repeat:
     265             :  * call predicate
     266             :  * increment position
     267             :  * if position <= size of current node-set, goto repeat
     268             :  * if child state result is empty, return
     269             :  * ...
     270             :  * \endcode
     271             :  *
     272             :  * So the selection of the nodes to fill the child state is a "simple"
     273             :  * instruction that implements the axis, that instruction loops through
     274             :  * the nodes from the DOM and add them to a list if they match the top
     275             :  * predicates: the prefix and the tag name.
     276             :  *
     277             :  * The calculation of the predicate, however, is the equivalent of a
     278             :  * recursive call to the whole process with the current node as the
     279             :  * context node. The return value of the predicate function is used
     280             :  * to know whether the node considered as the context node is kept
     281             :  * in the list. (Note that we cannot remove the node from the list
     282             :  * until all the nodes in that one list were processed of functions
     283             :  * such as count() and last() would fail misarably. Instead we use a
     284             :  * result list and replace the current list with that result list
     285             :  * before processing the next predicate.) Also, in the compiled
     286             :  * form, a predicate is a function since we need to be able to call the
     287             :  * same predicate over and over again with each child node.
     288             :  *
     289             :  * The resulting XPath program is very similar to what you'd get in
     290             :  * a forth language program. We use a stack to compute the current
     291             :  * expression and we have the equivalent of a stack for states (when
     292             :  * we create a child state, we simply make use of the next state in
     293             :  * a vector of states, adding a new state if the last one was already
     294             :  * in use.)
     295             :  *
     296             :  * The following are the instructions used to run our programs. Note
     297             :  * that in memory those instructions are bytes.
     298             :  *
     299             :  * The different types supported:
     300             :  *
     301             :  * \li boolean
     302             :  * \li integer
     303             :  * \li double
     304             :  * \li string
     305             :  * \li node-set
     306             :  *
     307             :  * \code
     308             :  * // stack instructions
     309             :  * push_true
     310             :  * push_false
     311             :  * push_zero
     312             :  * push_byte (1 byte)
     313             :  * push_short (2 bytes)
     314             :  * push_long (4 bytes)
     315             :  * push_longlong (8 bytes)
     316             :  * push_double_zero
     317             :  * push_double
     318             :  * push_empty_string
     319             :  * push_any (string "*")
     320             :  * push_string
     321             :  * push_empty_set
     322             :  * swap # (# is 0 to 9 meaning: apply to 'top of stack + #')
     323             :  * pop #
     324             :  * dup #
     325             :  *
     326             :  * // change Program Counter (pop 1 integer for offset)
     327             :  * call
     328             :  * return
     329             :  * return_if_true (pop 1 boolean item)
     330             :  * return_if_false (pop 1 boolean item)
     331             :  * jump
     332             :  * jump_if_true (pop 1 boolean item)
     333             :  * jump_if_false (pop 1 boolean item)
     334             :  * jump_if_zero (pop 1 number item)
     335             :  *
     336             :  * // state management
     337             :  * clone_state
     338             :  * new_state
     339             :  * get_position
     340             :  * set_position
     341             :  * get_node_set
     342             :  * set_node_set
     343             :  * get_result
     344             :  * set_result
     345             :  *
     346             :  * // applying entry, full (pop axis, pop node type, pop prefix, pop local part)
     347             :  * // popped axis: ancestor, ancestor-or-self, attribute, child,
     348             :  * //              descendant, descendant-or-self, following,
     349             :  * //              following, following-sibling, namespace, parent,
     350             :  * //              preceding, preceding-sibling, self
     351             :  * // popped node type: node, comment, processing-instruction, text
     352             :  * axis
     353             :  *
     354             :  * // variable handling
     355             :  * get_variable -- pop name, get variable, return value
     356             :  * set_variable -- pop name, pop value, set variable
     357             :  *
     358             :  * // arithmetic, logic, relational, ...
     359             :  * // pop one or two objects, apply operation, push result on the stack
     360             :  * add
     361             :  * subtract
     362             :  * increment
     363             :  * decrement
     364             :  * multiply
     365             :  * divide
     366             :  * modulo
     367             :  * negate
     368             :  * or
     369             :  * and
     370             :  * xor
     371             :  * not
     372             :  * equal
     373             :  * not_equal
     374             :  * less_than
     375             :  * less_or_equal
     376             :  * greater_than
     377             :  * greater_or_equal
     378             :  * node_set_size
     379             :  * append_node_set
     380             :  * interset_node_set
     381             :  * except_node_set
     382             :  * \endcode
     383             :  *
     384             :  * Example of the "loop" of the UnionExpr:
     385             :  *
     386             :  * \code
     387             :  * ; we assume that the class initializes an initial state
     388             :  * label start_program:
     389             :  * ; repeat union code from here
     390             :  * {insert path_expr_123 here--this does not need to be a sub-function}
     391             :  * ; WARNING: the following 3 instructions do not apply if the UnionExpr
     392             :  * ;          does not include a 'union' or '|' operator; this is very
     393             :  * ;          important since append_node_set does not accept but node sets
     394             :  * get_result
     395             :  * append_node_set
     396             :  * set_result
     397             :  * ; repeat for each entry
     398             :  * get_result
     399             :  * return
     400             :  * \endcode
     401             :  *
     402             :  * Example of the loop of a PathExpr:
     403             :  *
     404             :  * \code
     405             :  * label path_expr_123: ; some PathExpr
     406             :  * new_state
     407             :  * -- repeat PathExpr code from here
     408             :  * push "page"
     409             :  * push_any
     410             :  * push "node"
     411             :  * push "child"
     412             :  * axis
     413             :  * get_node_set
     414             :  * node_set_size
     415             :  * jump_if_zero exit
     416             :  * push_integer 1 ; these two lines probably represent the default position?
     417             :  * set_position
     418             :  * -- repeat Predicate code from here
     419             :  * label next:
     420             :  * call predicate ; some predicate function...
     421             :  * get_position
     422             :  * increment
     423             :  * dup
     424             :  * set_position
     425             :  * get_size
     426             :  * less_or_equal
     427             :  * jump_if_true next
     428             :  * get_result
     429             :  * node_set_size
     430             :  * jump_if_zero exit
     431             :  * get_result
     432             :  * set_node_set
     433             :  * push_empty_set
     434             :  * set_result
     435             :  * ; repeat with the each predicate
     436             :  * ; then repeat with the next path entry
     437             :  * label exit:
     438             :  * get_node_set
     439             :  * delete_state
     440             :  * return
     441             :  * \endcode
     442             :  */
     443             : 
     444             : 
     445             : /** \typedef QDomXPath::instruction_t
     446             :  * \brief Instructions composed the program once the XPath is compiled.
     447             :  *
     448             :  * An XPath is composed of many elements. In order to make it easy to
     449             :  * process an XPath against XML data, we compile the XPath to a byte
     450             :  * code language, which is defined as a vector of bytes representing
     451             :  * instructions, sizes, or immediate data.
     452             :  *
     453             :  * This works along an execution environment structure that keeps track
     454             :  * of the data (list of nodes and current status in general.) The status
     455             :  * uses a stack to handle expressions as with the forth language.
     456             :  *
     457             :  * We use a current state as well as the stack. The current state is
     458             :  * always accessible (i.e. it is like having access to a variable.)
     459             :  */
     460             : 
     461             : 
     462             : /** \brief Implementation of the DOM based XPath.
     463             :  *
     464             :  * This class is used to implement the internals of the XPath based
     465             :  * on a DOM. The class is an xpath 1.0 parser which makes use of a DOM
     466             :  * as its source of content. This is different from the standard XPath
     467             :  * implementation offered by Qt which only works on an XML stream.
     468             :  *
     469             :  * This implementation is specifically adapted for Snap! since Snap!
     470             :  * works with DOMs.
     471             :  */
     472           0 : class QDomXPath::QDomXPathImpl
     473             : {
     474             : public:
     475             : 
     476             : 
     477             : /** \brief The character type used by this class.
     478             :  *
     479             :  * The character type in case it were to change in the future to a UCS-4
     480             :  * character.
     481             :  */
     482             : typedef ushort  char_t;
     483             : 
     484             : /** \brief End of input indicator.
     485             :  *
     486             :  * While reading the input (f_in) characters are returned. Once the last
     487             :  * character is reached, the END_OF_PATH value is returned instead.
     488             :  *
     489             :  * Note that this -1 (or 0xFFFF) is not a valid XML character, it will
     490             :  * not detect END_OF_PATH at the wrong time.
     491             :  */
     492             : static const char_t END_OF_PATH = static_cast<char_t>(-1);
     493             : 
     494             : /** \brief Structure that holds the token information.
     495             :  *
     496             :  * This structure is used when parsing a token. By default it is
     497             :  * marked as undefined. The token can be tested with the bool
     498             :  * operator (i.e. if(token) ...) to know whether it is defined
     499             :  * (true) or undefined (false).
     500             :  */
     501           0 : struct token_t
     502             : {
     503             :     /** \brief List of tokens.
     504             :      *
     505             :      * This list of token is very large since The XML Path
     506             :      * defines a rather large number of function and other
     507             :      * names to be used to query an XML document node.
     508             :      */
     509             :     enum class tok_t
     510             :     {
     511             :         TOK_UNDEFINED,
     512             :         TOK_INVALID,
     513             : 
     514             :         TOK_OPEN_PARENTHESIS,
     515             :         TOK_CLOSE_PARENTHESIS,
     516             :         TOK_OPEN_SQUARE_BRACKET,
     517             :         TOK_CLOSE_SQUARE_BRACKET,
     518             :         TOK_DOT,
     519             :         TOK_DOUBLE_DOT,
     520             :         TOK_AT,
     521             :         TOK_COMMA,
     522             :         TOK_COLON,
     523             :         TOK_DOUBLE_COLON,
     524             :         TOK_SLASH,
     525             :         TOK_DOUBLE_SLASH,
     526             :         TOK_PIPE,
     527             :         TOK_PLUS,
     528             :         TOK_MINUS,
     529             :         TOK_EQUAL,
     530             :         TOK_NOT_EQUAL,
     531             :         TOK_LESS_THAN,
     532             :         TOK_LESS_OR_EQUAL,
     533             :         TOK_GREATER_THAN,
     534             :         TOK_GREATER_OR_EQUAL,
     535             :         TOK_ASTERISK,
     536             :         TOK_DOLLAR,
     537             :         TOK_STRING,
     538             :         TOK_INTEGER,
     539             :         TOK_REAL,
     540             :         TOK_OPERATOR_AND,
     541             :         TOK_OPERATOR_OR,
     542             :         TOK_OPERATOR_MOD,
     543             :         TOK_OPERATOR_DIV,
     544             :         TOK_NODE_TYPE_COMMENT,
     545             :         TOK_NODE_TYPE_TEXT,
     546             :         TOK_NODE_TYPE_PROCESSING_INSTRUCTION,
     547             :         TOK_NODE_TYPE_NODE,
     548             :         TOK_AXIS_NAME_ANCESTOR,
     549             :         TOK_AXIS_NAME_ANCESTOR_OR_SELF,
     550             :         TOK_AXIS_NAME_ATTRIBUTE,
     551             :         TOK_AXIS_NAME_CHILD,
     552             :         TOK_AXIS_NAME_DESCENDANT,
     553             :         TOK_AXIS_NAME_DESCENDANT_OR_SELF,
     554             :         TOK_AXIS_NAME_FOLLOWING,
     555             :         TOK_AXIS_NAME_FOLLOWING_SIBLING,
     556             :         TOK_AXIS_NAME_NAMESPACE,
     557             :         TOK_AXIS_NAME_PARENT,
     558             :         TOK_AXIS_NAME_PRECEDING,
     559             :         TOK_AXIS_NAME_PRECEDING_SIBLING,
     560             :         TOK_AXIS_NAME_SELF,
     561             :         TOK_PREFIX,
     562             :         TOK_NCNAME
     563             :     };
     564             : 
     565             :     /** \brief Test whether the token is defined.
     566             :      *
     567             :      * This function checks whether the token is defined. If defined,
     568             :      * it returns true.
     569             :      *
     570             :      * \return true if the token is not TOK_UNDEFINED.
     571             :      */
     572           0 :     operator bool ()
     573             :     {
     574           0 :         return f_token != tok_t::TOK_UNDEFINED;
     575             :     }
     576             : 
     577             :     /** \brief Test whether the token is undefined.
     578             :      *
     579             :      * This function checks whether the token is undefined. If not defined,
     580             :      * it returns true.
     581             :      *
     582             :      * \return true if the token is TOK_UNDEFINED.
     583             :      */
     584             :     bool operator ! ()
     585             :     {
     586             :         return f_token == tok_t::TOK_UNDEFINED;
     587             :     }
     588             : 
     589             :     /** \brief Make the token undefined.
     590             :      *
     591             :      * This function marks the token as being undefined.
     592             :      */
     593           0 :     void reset()
     594             :     {
     595           0 :         f_token = tok_t::TOK_UNDEFINED;
     596           0 :     }
     597             : 
     598             :     tok_t           f_token = tok_t::TOK_UNDEFINED;
     599             :     QString         f_string = QString();
     600             :     int64_t         f_integer = 0;
     601             :     double          f_real = 0.0;
     602             : };
     603             : 
     604             : /** \brief An array of tokens.
     605             :  *
     606             :  * The typedef defines an array of token which is generally used to
     607             :  * represent the stack.
     608             :  */
     609             : typedef QVector<token_t> token_vector_t;
     610             : 
     611             : 
     612             : /** \brief A map of label offsets.
     613             :  *
     614             :  * This map is used to define offset names and their offset in the program.
     615             :  */
     616             : typedef QMap<QString, uint32_t> label_offsets_t;
     617             : 
     618             : 
     619             : /** \brief Jump to Label structure.
     620             :  *
     621             :  * Whenever a jump to a future label is added, we need to "fix" the push
     622             :  * integer at a later time. This is done by saving the label in this way
     623             :  * and later by searching for it to fix it.
     624             :  */
     625             : typedef QVector<int> jump_to_label_vector_t;
     626             : 
     627             : 
     628             : /** \brief An array of future labels.
     629             :  *
     630             :  * The list of future labels is saved in a vector. Whenever you mark
     631             :  * the label, the future labels are corrected and removed from the
     632             :  * list. Since the calls are "recursive", this table can grow pretty
     633             :  * big and maybe we'll use a map at a later time.
     634             :  */
     635             : typedef QMap<QString, jump_to_label_vector_t> future_labels_t;
     636             : 
     637             : 
     638             : /** \brief An array of labels.
     639             :  *
     640             :  * This list of labels is used within the parsing of a location path.
     641             :  * Labels are created before each axis and "released" when the end of
     642             :  * the location path is reached.
     643             :  *
     644             :  * We do not need more than the offset at the time the label is created
     645             :  * since it is created first and jumped to later.
     646             :  */
     647             : typedef QVector<int> labels_t;
     648             : 
     649             : 
     650             : /** \brief Current context while running.
     651             :  *
     652             :  * While running the program, the context defines the current status of
     653             :  * the process. It includes the current set of nodes, the context node
     654             :  * (i.e. f_nodes[f_position]) and the set of nodes in the result being
     655             :  * computed right now.
     656             :  *
     657             :  * By default the position is set to -1 which means "not set"
     658             :  * and it cannot be used (if accessed [as in INST_GET_POSITION],
     659             :  * you get an error.)
     660             :  */
     661           0 : struct context_t
     662             : {
     663             :     int32_t                     f_position = -1;
     664             :     QDomXPath::node_vector_t    f_nodes = QDomXPath::node_vector_t();
     665             :     QDomXPath::node_vector_t    f_result = QDomXPath::node_vector_t();
     666             : };
     667             : 
     668             : 
     669             : /** \brief An array of contexts.
     670             :  *
     671             :  * Whenever a new context is created (i.e. when a new entry in a list of
     672             :  * entries starts execution) then it is added at the back of this array.
     673             :  *
     674             :  * The program as a whole has one stack of states.
     675             :  */
     676             : typedef QVector<context_t> context_vector_t;
     677             : 
     678             : 
     679             : /** \brief A sub-class of the variant_t definition.
     680             :  *
     681             :  * The atomic values are defined in a separate class so that way we can
     682             :  * create sets of atomic values without being bothered by sub-sets which
     683             :  * are not supported by XPath 2.0 anyway (i.e. ((1, 2), (3, 4)) becomes
     684             :  * (1, 2, 3, 4) which is one set.)
     685             :  */
     686           0 : class atomic_value_t
     687             : {
     688             : public:
     689             :     /** \brief Atomic types.
     690             :      *
     691             :      * The atomic types are used internally to determine the type of
     692             :      * variant the data is. The type is defined in the atomic_value_t
     693             :      * since it is necessary here. It could be defined outside too
     694             :      * although this way it defines it in a namespace like environment.
     695             :      */
     696             :     enum class type_t
     697             :     {
     698             :         ATOMIC_TYPE_UNDEFINED,
     699             : 
     700             :         ATOMIC_TYPE_NULL,
     701             :         ATOMIC_TYPE_END_OF_ARGUMENTS,
     702             :         ATOMIC_TYPE_BOOLEAN,
     703             :         ATOMIC_TYPE_INTEGER,
     704             :         //ATOMIC_TYPE_DECIMAL,
     705             :         ATOMIC_TYPE_SINGLE,
     706             :         ATOMIC_TYPE_DOUBLE,
     707             :         ATOMIC_TYPE_STRING,
     708             : 
     709             :         // we include the non-atomic types too
     710             :         ATOMIC_TYPE_SET,
     711             :         ATOMIC_TYPE_NODE_SET
     712             :         //ATOMIC_TYPE_CONTEXT
     713             :     };
     714             : 
     715             :     /** \brief Initialize the atomic value.
     716             :      *
     717             :      * This function sets the type of the atomic value to NULL which means
     718             :      * that it is undefined. Trying to get a value when an atomic value
     719             :      * is NULL generates an error by default although if the cast is set
     720             :      * to true.
     721             :      */
     722           0 :     atomic_value_t()
     723           0 :         : f_type(type_t::ATOMIC_TYPE_NULL)
     724             :         //, f_boolean(false) -- not necessary -- not actually used for now
     725             :         //, f_integer(0) -- not necessary
     726             :         //, f_decimal(0) -- not necessary -- not actually used for now
     727             :         //, f_single(0.0f) -- not necessary
     728             :         //, f_doulbe(0.0) -- not necessary
     729             :         //, f_string("") -- auto-init
     730             :     {
     731           0 :     }
     732             : 
     733             :     /** \brief Copy a value in another.
     734             :      *
     735             :      * Because some parameters may not be defined, the copy operator is
     736             :      * overloaded to only copy what is necessary and avoid errors.
     737             :      *
     738             :      * \param[in] rhs  The right hand side to copy in this value.
     739             :      */
     740           0 :     atomic_value_t(atomic_value_t const& rhs)
     741           0 :         : f_type(rhs.f_type)
     742             :         //, f_boolean(false) -- handled below if necessary -- not actually used for now
     743             :         //, f_integer(0) -- handled below if necessary
     744             :         //, f_decimal(0) -- handled below if necessary -- not actually used for now
     745             :         //, f_single(0.0f) -- handled below if necessary
     746             :         //, f_doulbe(0.0) -- handled below if necessary
     747             :         //, f_string("") -- handled below if necessary
     748             :     {
     749           0 :         switch(f_type)
     750             :         {
     751           0 :         case type_t::ATOMIC_TYPE_NULL:
     752             :         case type_t::ATOMIC_TYPE_END_OF_ARGUMENTS:
     753             :             // no data to copy
     754           0 :             break;
     755             : 
     756           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
     757             :             //f_boolean = rhs.f_boolean; // using integer instead for now
     758             :         case type_t::ATOMIC_TYPE_INTEGER:
     759           0 :             f_integer = rhs.f_integer;
     760           0 :             break;
     761             : 
     762           0 :         case type_t::ATOMIC_TYPE_SINGLE:
     763           0 :             f_single = rhs.f_single;
     764           0 :             break;
     765             : 
     766           0 :         case type_t::ATOMIC_TYPE_DOUBLE:
     767           0 :             f_double = rhs.f_double;
     768           0 :             break;
     769             : 
     770           0 :         case type_t::ATOMIC_TYPE_STRING:
     771           0 :             f_string = rhs.f_string;
     772           0 :             break;
     773             : 
     774           0 :         case type_t::ATOMIC_TYPE_SET:
     775             :         case type_t::ATOMIC_TYPE_NODE_SET:
     776           0 :             break;
     777             : 
     778             :         //case type_t::ATOMIC_TYPE_UNDEFINED:
     779           0 :         default:
     780           0 :             throw QDomXPathException_NotImplemented(QString("copying of type %1 is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
     781             : 
     782             :         }
     783           0 :     }
     784             : 
     785             :     /** \brief Copy a value in another.
     786             :      *
     787             :      * Because some parameters may not be defined, the copy operator is
     788             :      * overloaded to only copy what is necessary and avoid errors.
     789             :      *
     790             :      * \param[in] rhs  The right hand side to copy in this value.
     791             :      *
     792             :      * \return A reference to this object.
     793             :      */
     794           0 :     atomic_value_t& operator = (atomic_value_t const& rhs)
     795             :     {
     796           0 :         if(this != &rhs)
     797             :         {
     798           0 :             f_type = rhs.f_type;
     799           0 :             switch(f_type)
     800             :             {
     801           0 :             case type_t::ATOMIC_TYPE_NULL:
     802             :             case type_t::ATOMIC_TYPE_END_OF_ARGUMENTS:
     803             :                 // no data to copy
     804           0 :                 break;
     805             : 
     806           0 :             case type_t::ATOMIC_TYPE_BOOLEAN:
     807             :                 //f_boolean = rhs.f_boolean; // using integer instead for now
     808             :             case type_t::ATOMIC_TYPE_INTEGER:
     809           0 :                 f_integer = rhs.f_integer;
     810           0 :                 break;
     811             : 
     812           0 :             case type_t::ATOMIC_TYPE_SINGLE:
     813           0 :                 f_single = rhs.f_single;
     814           0 :                 break;
     815             : 
     816           0 :             case type_t::ATOMIC_TYPE_DOUBLE:
     817           0 :                 f_double = rhs.f_double;
     818           0 :                 break;
     819             : 
     820           0 :             case type_t::ATOMIC_TYPE_STRING:
     821           0 :                 f_string = rhs.f_string;
     822           0 :                 break;
     823             : 
     824           0 :             case type_t::ATOMIC_TYPE_SET:
     825             :             case type_t::ATOMIC_TYPE_NODE_SET:
     826           0 :                 break;
     827             : 
     828             :             //case type_t::ATOMIC_TYPE_UNDEFINED:
     829           0 :             default:
     830           0 :                 throw QDomXPathException_NotImplemented(QString("copying of type %1 is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
     831             : 
     832             :             }
     833             :         }
     834           0 :         return *this;
     835             :     }
     836             : 
     837             :     /** \brief Get the type.
     838             :      *
     839             :      * Return the type of this atomic value. This determines the get<name>()
     840             :      * function that can be called to retrieve the value as is. Other
     841             :      * get<name>() functions can also be called, but only to cast the value
     842             :      * and in that case the cast parameter must be set to true or the
     843             :      * function throws a QDomXPathException_WrongType exception.
     844             :      *
     845             :      * To test whether an atomtic_value_t is NULL, use the getType()
     846             :      * and compare it with type_t::ATOMIC_TYPE_NULL.
     847             :      */
     848           0 :     type_t getType() const
     849             :     {
     850           0 :         return f_type;
     851             :     }
     852             : 
     853             :     /** \brief Set the value to NULL.
     854             :      *
     855             :      * This function sets the value to NULL. NULL is the default value
     856             :      * of an atomic value object.
     857             :      *
     858             :      * All other types are lost after this call.
     859             :      */
     860             :     void setValue()
     861             :     {
     862             :         f_type = type_t::ATOMIC_TYPE_NULL;
     863             :     }
     864             : 
     865             :     /** \brief Set the value to End of Arguments.
     866             :      *
     867             :      * This function sets the value to End of Arguments. This special value
     868             :      * is used to end the list of arguments to a function. Note that it
     869             :      * is always expected to be popped by the function being called and
     870             :      * not by an expression. This is why there is not even one convertion
     871             :      * function for this special type.
     872             :      */
     873           0 :     void setEndOfArguments()
     874             :     {
     875           0 :         f_type = type_t::ATOMIC_TYPE_END_OF_ARGUMENTS;
     876           0 :     }
     877             : 
     878             :     /** \brief Retrieve the value as a Boolean.
     879             :      *
     880             :      * The function retrieves the atomic value as a Boolean. If the value
     881             :      * is not a Boolean and the \p cast parameter is not set to true,
     882             :      * then the function generates an exception. Otherwise the function
     883             :      * attempts to convert the value to a Boolean.
     884             :      *
     885             :      * \exception QDomXPathException_WrongType
     886             :      * This exception is raised if the atomic type is not
     887             :      * type_t::ATOMIC_TYPE_BOOLEAN.
     888             :      *
     889             :      * \param[in] cast  Whether to cast the value if it is not a Boolean.
     890             :      *
     891             :      * \return The value as a Boolean.
     892             :      */
     893           0 :     bool getBooleanValue(bool cast = false) const
     894             :     {
     895           0 :         if(f_type != type_t::ATOMIC_TYPE_BOOLEAN)
     896             :         {
     897           0 :             if(!cast)
     898             :             {
     899           0 :                 throw QDomXPathException_WrongType(QString("atomic type is %1, when a Boolean was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
     900             :             }
     901             :         }
     902           0 :         switch(f_type)
     903             :         {
     904           0 :         case type_t::ATOMIC_TYPE_NULL:
     905           0 :             return false;
     906             : 
     907           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
     908             :             //return f_boolean;
     909             :         case type_t::ATOMIC_TYPE_INTEGER:
     910           0 :             return f_integer != 0;
     911             : 
     912             : #pragma GCC diagnostic push
     913             : #pragma GCC diagnostic ignored "-Wfloat-equal"
     914           0 :         case type_t::ATOMIC_TYPE_SINGLE:
     915           0 :             return 0.0f != f_single;
     916             : 
     917           0 :         case type_t::ATOMIC_TYPE_DOUBLE:
     918           0 :             return 0.0 != f_double;
     919             : #pragma GCC diagnostic pop
     920             : 
     921           0 :         case type_t::ATOMIC_TYPE_STRING:
     922             :             // TODO -- I think this is totally wrong; if I'm correct it
     923             :             //         should interpret the string as true or false and
     924             :             //         not whether the string is empty (will test later)
     925           0 :             return !f_string.isEmpty();
     926             : 
     927           0 :         default:
     928             :             // this should be done in the previous level
     929           0 :             throw QDomXPathException_NotImplemented(QString("type %1 to Boolean conversion is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
     930             : 
     931             :         }
     932             :     }
     933             : 
     934             :     /** \brief Set the value to the specified Boolean.
     935             :      *
     936             :      * This function sets the atomic value to the specified Boolean
     937             :      * and sets the type to type_t::ATOMIC_TYPE_BOOLEAN.
     938             :      *
     939             :      * All other types are lost after this call.
     940             :      *
     941             :      * \param[in] b  The new Boolean value for this atomtic type.
     942             :      */
     943           0 :     void setValue(const bool b)
     944             :     {
     945           0 :         f_type = type_t::ATOMIC_TYPE_BOOLEAN;
     946             :         //f_boolean = b;
     947           0 :         f_integer = b ? 1 : 0;
     948           0 :     }
     949             : 
     950             :     /** \brief Retrieve the value as an Integer.
     951             :      *
     952             :      * The function retrieves the atomic value as an Integer. If the value
     953             :      * is not an integer and the \p cast parameter is not set to true,
     954             :      * then the function generates an exception. Otherwise the function
     955             :      * attempts to convert the value to an integer.
     956             :      *
     957             :      * \exception QDomXPathException_WrongType
     958             :      * This exception is raised if the atomic type is not
     959             :      * type_t::ATOMIC_TYPE_INTEGER.
     960             :      *
     961             :      * \param[in] cast  Whether to cast the value if it is not an Integer.
     962             :      *
     963             :      * \return The value as an Integer.
     964             :      */
     965           0 :     int64_t getIntegerValue(bool cast = false) const
     966             :     {
     967           0 :         if(f_type != type_t::ATOMIC_TYPE_INTEGER)
     968             :         {
     969           0 :             if(!cast)
     970             :             {
     971           0 :                 throw QDomXPathException_WrongType(QString("atomic type is %1, when an Integer was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
     972             :             }
     973             :         }
     974           0 :         switch(f_type)
     975             :         {
     976           0 :         case type_t::ATOMIC_TYPE_NULL:
     977           0 :             return 0;
     978             : 
     979           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
     980           0 :             return f_integer != 0 ? 1 : 0;
     981             : 
     982           0 :         case type_t::ATOMIC_TYPE_INTEGER:
     983           0 :             return f_integer;
     984             : 
     985           0 :         case type_t::ATOMIC_TYPE_SINGLE:
     986           0 :             return static_cast<int64_t>(std::floor(f_single));
     987             : 
     988           0 :         case type_t::ATOMIC_TYPE_DOUBLE:
     989           0 :             return static_cast<int64_t>(std::floor(f_double));
     990             : 
     991           0 :         case type_t::ATOMIC_TYPE_STRING:
     992             :             // TODO -- create a "correct" string to integer convertion
     993           0 :             return static_cast<int64_t>(atol(f_string.toUtf8().data()));
     994             : 
     995           0 :         default:
     996             :             // this should be done in the previous level
     997           0 :             throw QDomXPathException_NotImplemented(QString("type %1 to integer conversion is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
     998             : 
     999             :         }
    1000             :     }
    1001             : 
    1002             :     /** \brief Set the value to the specified integer.
    1003             :      *
    1004             :      * This function sets the atomic value to the specified integer
    1005             :      * and sets the type to type_t::ATOMIC_TYPE_INTEGER.
    1006             :      *
    1007             :      * All other types are lost after this call.
    1008             :      *
    1009             :      * \param[in] integer  The new integer value for this atomtic type.
    1010             :      */
    1011           0 :     void setValue(const int64_t integer)
    1012             :     {
    1013           0 :         f_type = type_t::ATOMIC_TYPE_INTEGER;
    1014           0 :         f_integer = integer;
    1015           0 :     }
    1016             : 
    1017             :     //void setValue(const QDecimal& decimal)
    1018             :     //{
    1019             :     //    f_type = type_t::ATOMIC_TYPE_DECIMAL;
    1020             :     //    f_decimal = decimal;
    1021             :     //}
    1022             : 
    1023             :     /** \brief Retrieve the value as a Single.
    1024             :      *
    1025             :      * The function retrieves the atomic value as a Single. If the value
    1026             :      * is not a Single and the \p cast parameter is not set to true,
    1027             :      * then the function generates an exception. Otherwise the function
    1028             :      * attempts to convert the value to a Single.
    1029             :      *
    1030             :      * \exception QDomXPathException_WrongType
    1031             :      * This exception is raised if the atomic type is not
    1032             :      * type_t::ATOMIC_TYPE_SINGLE.
    1033             :      *
    1034             :      * \param[in] cast  Whether to cast the value if it is not a Single.
    1035             :      *
    1036             :      * \return The value as a Single.
    1037             :      */
    1038           0 :     float getSingleValue(bool cast = false) const
    1039             :     {
    1040           0 :         if(f_type != type_t::ATOMIC_TYPE_SINGLE)
    1041             :         {
    1042           0 :             if(!cast)
    1043             :             {
    1044           0 :                 throw QDomXPathException_WrongType(QString("atomic type is %1, when a Single was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1045             :             }
    1046             :         }
    1047           0 :         switch(f_type)
    1048             :         {
    1049           0 :         case type_t::ATOMIC_TYPE_NULL:
    1050           0 :             return 0.0f;
    1051             : 
    1052           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
    1053           0 :             return f_integer == 0 ? 0.0f : 1.0f;
    1054             : 
    1055           0 :         case type_t::ATOMIC_TYPE_INTEGER:
    1056           0 :             return static_cast<float>(f_integer);
    1057             : 
    1058           0 :         case type_t::ATOMIC_TYPE_SINGLE:
    1059           0 :             return f_single;
    1060             : 
    1061           0 :         case type_t::ATOMIC_TYPE_DOUBLE:
    1062           0 :             return static_cast<float>(f_double);
    1063             : 
    1064           0 :         case type_t::ATOMIC_TYPE_STRING:
    1065           0 :             return static_cast<float>(atof(f_string.toUtf8().data()));
    1066             : 
    1067           0 :         default:
    1068             :             // this should be done in the previous level
    1069           0 :             throw QDomXPathException_NotImplemented(QString("type %1 to single is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1070             : 
    1071             :         }
    1072             :     }
    1073             : 
    1074             :     /** \brief Set the value to the specified Single.
    1075             :      *
    1076             :      * This function sets the atomic value to the specified Single
    1077             :      * and sets the type to type_t::ATOMIC_TYPE_SINGLE.
    1078             :      *
    1079             :      * All other types are lost after this call.
    1080             :      *
    1081             :      * \param[in] real  The new Single value for this atomtic type.
    1082             :      */
    1083           0 :     void setValue(const float real)
    1084             :     {
    1085           0 :         f_type = type_t::ATOMIC_TYPE_SINGLE;
    1086           0 :         f_single = real;
    1087           0 :     }
    1088             : 
    1089             :     /** \brief Retrieve the value as a Double.
    1090             :      *
    1091             :      * The function retrieves the atomic value as a Double. If the value
    1092             :      * is not a Double and the \p cast parameter is not set to true,
    1093             :      * then the function generates an exception. Otherwise the function
    1094             :      * attempts to convert the value to a Double.
    1095             :      *
    1096             :      * \exception QDomXPathException_WrongType
    1097             :      * This exception is raised if the atomic type is not
    1098             :      * type_t::ATOMIC_TYPE_DOUBLE.
    1099             :      *
    1100             :      * \param[in] cast  Whether to cast the value if it is not a Double.
    1101             :      *
    1102             :      * \return The value as a double.
    1103             :      */
    1104           0 :     double getDoubleValue(bool cast = false) const
    1105             :     {
    1106           0 :         if(f_type != type_t::ATOMIC_TYPE_DOUBLE)
    1107             :         {
    1108           0 :             if(!cast)
    1109             :             {
    1110           0 :                 throw QDomXPathException_WrongType(QString("atomic type is %1, when a Double was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1111             :             }
    1112             :         }
    1113           0 :         switch(f_type)
    1114             :         {
    1115           0 :         case type_t::ATOMIC_TYPE_NULL:
    1116           0 :             return 0.0;
    1117             : 
    1118           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
    1119           0 :             return f_integer == 0 ? 0.0 : 1.0;
    1120             : 
    1121           0 :         case type_t::ATOMIC_TYPE_INTEGER:
    1122           0 :             return static_cast<double>(f_integer);
    1123             : 
    1124           0 :         case type_t::ATOMIC_TYPE_SINGLE:
    1125           0 :             return static_cast<double>(f_single);
    1126             : 
    1127           0 :         case type_t::ATOMIC_TYPE_DOUBLE:
    1128           0 :             return f_double;
    1129             : 
    1130           0 :         case type_t::ATOMIC_TYPE_STRING:
    1131             :             // TODO -- properly convert the string (as per the XPath
    1132             :             //         documentation) we whouls have an external function
    1133             :             //         for the purpose so any convertion uses the same code
    1134           0 :             return atof(f_string.toUtf8().data());
    1135             : 
    1136           0 :         default:
    1137             :             // this should be done in the previous level
    1138           0 :             throw QDomXPathException_NotImplemented(QString("type %1 to double conversion is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1139             : 
    1140             :         }
    1141             :     }
    1142             : 
    1143             :     /** \brief Set the value to the specified double.
    1144             :      *
    1145             :      * This function sets the atomic value to the specified double
    1146             :      * and sets the type to type_t::ATOMIC_TYPE_DOUBLE.
    1147             :      *
    1148             :      * All other types are lost after this call.
    1149             :      *
    1150             :      * \param[in] real  The new double value for this atomtic type.
    1151             :      */
    1152           0 :     void setValue(const double real)
    1153             :     {
    1154           0 :         f_type = type_t::ATOMIC_TYPE_DOUBLE;
    1155           0 :         f_double = real;
    1156           0 :     }
    1157             : 
    1158             :     /** \brief Retrieve the value as a String.
    1159             :      *
    1160             :      * The function retrieves the atomic value as a String. If the value
    1161             :      * is not a String and the \p cast parameter is not set to true,
    1162             :      * then the function generates an exception. Otherwise the function
    1163             :      * attempts to convert the value to a String.
    1164             :      *
    1165             :      * \exception QDomXPathException_WrongType
    1166             :      * This exception is raised if the atomic type is not
    1167             :      * type_t::ATOMIC_TYPE_STRING.
    1168             :      *
    1169             :      * \param[in] cast  Whether to cast the value if it is not a String.
    1170             :      *
    1171             :      * \return The value as a String.
    1172             :      */
    1173           0 :     QString getStringValue(bool cast = false) const
    1174             :     {
    1175           0 :         if(f_type != type_t::ATOMIC_TYPE_STRING)
    1176             :         {
    1177           0 :             if(!cast)
    1178             :             {
    1179           0 :                 throw QDomXPathException_WrongType(QString("atomic type is %1, when a String was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1180             :             }
    1181             :         }
    1182           0 :         switch(f_type)
    1183             :         {
    1184           0 :         case type_t::ATOMIC_TYPE_NULL:
    1185           0 :             return "null";
    1186             : 
    1187           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
    1188           0 :             return f_integer != 0 ? "true" : "false";
    1189             : 
    1190           0 :         case type_t::ATOMIC_TYPE_INTEGER:
    1191           0 :             return QString("%1").arg(f_integer);
    1192             : 
    1193           0 :         case type_t::ATOMIC_TYPE_SINGLE:
    1194           0 :             return QString("%1").arg(f_single);
    1195             : 
    1196           0 :         case type_t::ATOMIC_TYPE_DOUBLE:
    1197           0 :             return QString("%1").arg(f_double);
    1198             : 
    1199           0 :         case type_t::ATOMIC_TYPE_STRING:
    1200           0 :             return f_string;
    1201             : 
    1202           0 :         default:
    1203             :             // this should be done in the previous level
    1204           0 :             throw QDomXPathException_NotImplemented(QString("type %1 to string conversion is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1205             : 
    1206             :         }
    1207             :     }
    1208             : 
    1209             :     /** \brief Set the value to the specified string.
    1210             :      *
    1211             :      * This function sets the atomic value to the specified string
    1212             :      * and sets the type to type_t::ATOMIC_TYPE_STRING.
    1213             :      *
    1214             :      * All other types are lost after this call.
    1215             :      *
    1216             :      * \param[in] str  The new string value for this atomtic type.
    1217             :      */
    1218           0 :     void setValue(const QString& str)
    1219             :     {
    1220           0 :         f_type = type_t::ATOMIC_TYPE_STRING;
    1221           0 :         f_string = str;
    1222           0 :     }
    1223             : 
    1224             :     /** \brief Set the value to the specified string.
    1225             :      *
    1226             :      * This function sets the atomic value to the specified string
    1227             :      * and sets the type to type_t::ATOMIC_TYPE_STRING.
    1228             :      *
    1229             :      * All other types are lost after this call.
    1230             :      *
    1231             :      * \param[in] str  The new string value for this atomtic type.
    1232             :      */
    1233           0 :     void setValue(const char *str)
    1234             :     {
    1235           0 :         f_type = type_t::ATOMIC_TYPE_STRING;
    1236           0 :         f_string = QString::fromUtf8(str);
    1237           0 :     }
    1238             : 
    1239             : 
    1240             :     /** \brief Set the value to the specified string.
    1241             :      *
    1242             :      * This function sets the atomic value to the specified string
    1243             :      * and sets the type to type_t::ATOMIC_TYPE_STRING.
    1244             :      *
    1245             :      * All other types are lost after this call.
    1246             :      *
    1247             :      * \param[in] str  The new string value for this atomtic type.
    1248             :      */
    1249             :     void setValue(const wchar_t *str)
    1250             :     {
    1251             :         f_type = type_t::ATOMIC_TYPE_STRING;
    1252             :         f_string = QString::fromWCharArray(str);
    1253             :     }
    1254             : 
    1255             : 
    1256             :     /** \brief Set the value to the specified string.
    1257             :      *
    1258             :      * This function sets the atomic value to the specified string
    1259             :      * and sets the type to type_t::ATOMIC_TYPE_STRING.
    1260             :      *
    1261             :      * All other types are lost after this call.
    1262             :      *
    1263             :      * \param[in] str  The new string value for this atomtic type.
    1264             :      */
    1265             :     void setValue(const std::string& str)
    1266             :     {
    1267             :         f_type = type_t::ATOMIC_TYPE_STRING;
    1268             :         f_string = QString::fromUtf8(str.c_str());
    1269             :     }
    1270             : 
    1271             : 
    1272             : protected:
    1273             :     type_t                      f_type = type_t::ATOMIC_TYPE_UNDEFINED;
    1274             : 
    1275             : private:
    1276             :     //bool                        f_boolean = false; -- save some space by using integer 0 or 1
    1277             :     int64_t                     f_integer = 0;
    1278             :     // definition? http://www.w3.org/2002/ws/databinding/patterns/6/09/PrecisionDecimal/
    1279             :     //QDecimal                    f_decimal; // a 32:32 fix number (we need a fixed number class!)
    1280             :     float                       f_single = 0.0f;
    1281             :     double                      f_double = 0.0;
    1282             :     QString                     f_string = QString();
    1283             : };
    1284             : 
    1285             : 
    1286             : /** \brief Merge two types together to accelerate selections.
    1287             :  *
    1288             :  * This function is used to merge two types together so we can quickly
    1289             :  * select two types through the use of a switch statement.
    1290             :  *
    1291             :  * \param[in] a  The left type.
    1292             :  * \param[in] b  The right type.
    1293             :  *
    1294             :  * \return The two types merged in an int32_t.
    1295             :  */
    1296           0 : static constexpr int32_t merge_types(atomic_value_t::type_t a, atomic_value_t::type_t b) // we are inside a class, hence the 'static'
    1297             : {
    1298             :     return static_cast<int32_t>(a)
    1299           0 :         | (static_cast<int32_t>(b) << 16);
    1300             : }
    1301             : 
    1302             : 
    1303             : /** \brief An array of atomic value.
    1304             :  *
    1305             :  * This typedef allows us to create arrays of atomic values.
    1306             :  */
    1307             : typedef QVector<atomic_value_t> atomic_vector_t;
    1308             : 
    1309             : /** \brief The variant structure is used at execution time.
    1310             :  *
    1311             :  * The variant_t represents a value generally on the stack. It can also
    1312             :  * be viewed as the current set of nodes in a state and the current set
    1313             :  * of nodes in the result although for those we directly use node_vector_t
    1314             :  * because those are always sets of nodes.
    1315             :  */
    1316           0 : class variant_t : public atomic_value_t
    1317             : {
    1318             : public:
    1319             :     // need to have an explicit constructor so we can have a copy
    1320             :     // constructor as well...
    1321           0 :     variant_t()
    1322             :         //: atomic_value_t()
    1323             :         //, f_atomic() -- auto-init
    1324             :         //, f_set() -- auto-init
    1325             :         //, f_node_set() -- auto-init
    1326           0 :     {
    1327           0 :     }
    1328             : 
    1329           0 :     variant_t(variant_t const& rhs)
    1330           0 :         : atomic_value_t(rhs)
    1331             :     {
    1332           0 :         switch(f_type)
    1333             :         {
    1334           0 :         case type_t::ATOMIC_TYPE_NULL:
    1335             :         case type_t::ATOMIC_TYPE_END_OF_ARGUMENTS:
    1336             :         case type_t::ATOMIC_TYPE_BOOLEAN:
    1337             :         case type_t::ATOMIC_TYPE_INTEGER:
    1338             :         case type_t::ATOMIC_TYPE_SINGLE:
    1339             :         case type_t::ATOMIC_TYPE_DOUBLE:
    1340             :         case type_t::ATOMIC_TYPE_STRING:
    1341             :             // already handled, avoid the default: ...
    1342           0 :             break;
    1343             : 
    1344           0 :         case type_t::ATOMIC_TYPE_SET:
    1345           0 :             f_set = rhs.f_set;
    1346           0 :             break;
    1347             : 
    1348           0 :         case type_t::ATOMIC_TYPE_NODE_SET:
    1349           0 :             f_node_set = rhs.f_node_set;
    1350           0 :             break;
    1351             : 
    1352           0 :         default:
    1353             :             // this should be done in the previous level
    1354             :             // (i.e. this line should not be reachable)
    1355           0 :             throw QDomXPathException_NotImplemented(QString("copying of type %1 is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1356             : 
    1357             :         }
    1358           0 :     }
    1359             : 
    1360             :     /** \brief Copy a value in another.
    1361             :      *
    1362             :      * Because some parameters may not be defined, the copy operator is
    1363             :      * overloaded to only copy what is necessary and avoid errors.
    1364             :      *
    1365             :      * \param[in] rhs  The right hand side to copy in this value.
    1366             :      *
    1367             :      * \return A reference to this object.
    1368             :      */
    1369           0 :     variant_t& operator = (variant_t const& rhs)
    1370             :     {
    1371           0 :         if(this != &rhs)
    1372             :         {
    1373           0 :             f_type = rhs.f_type;
    1374           0 :             switch(f_type)
    1375             :             {
    1376           0 :             case type_t::ATOMIC_TYPE_NULL:
    1377             :             case type_t::ATOMIC_TYPE_END_OF_ARGUMENTS:
    1378             :             case type_t::ATOMIC_TYPE_BOOLEAN:
    1379             :             case type_t::ATOMIC_TYPE_INTEGER:
    1380             :             case type_t::ATOMIC_TYPE_SINGLE:
    1381             :             case type_t::ATOMIC_TYPE_DOUBLE:
    1382             :             case type_t::ATOMIC_TYPE_STRING:
    1383             :                 // ignore the result, we return *this below
    1384           0 :                 snap::NOTUSED(atomic_value_t::operator = (rhs));
    1385           0 :                 break;
    1386             : 
    1387           0 :             case type_t::ATOMIC_TYPE_SET:
    1388           0 :                 f_set = rhs.f_set;
    1389           0 :                 break;
    1390             : 
    1391           0 :             case type_t::ATOMIC_TYPE_NODE_SET:
    1392           0 :                 f_node_set = rhs.f_node_set;
    1393           0 :                 break;
    1394             : 
    1395             :             //case type_t::ATOMIC_TYPE_UNDEFINED:
    1396           0 :             default:
    1397           0 :                 throw QDomXPathException_NotImplemented(QString("copying of type %1 is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1398             : 
    1399             :             }
    1400             :         }
    1401           0 :         return *this;
    1402             :     }
    1403             : 
    1404             :     /** \brief Retrieve the Boolean value.
    1405             :      *
    1406             :      * This function retrieves the Boolean value from the variant. If
    1407             :      * the \p cast parameter is true, then the sets are also checked
    1408             :      * and return true if they are not empty.
    1409             :      *
    1410             :      * \param[in] cast  Whether to cast the value if not a Boolean.
    1411             :      *
    1412             :      * \return The Boolean value, or whatever value converted to a Boolean.
    1413             :      */
    1414           0 :     bool getBooleanValue(bool cast = false) const
    1415             :     {
    1416           0 :         if(cast)
    1417             :         {
    1418           0 :             switch(f_type)
    1419             :             {
    1420           0 :             case type_t::ATOMIC_TYPE_SET:
    1421             :                 // TODO -- do proper implementation
    1422           0 :                 return !f_set.isEmpty();
    1423             : 
    1424           0 :             case type_t::ATOMIC_TYPE_NODE_SET:
    1425             :                 // TODO -- do proper implementation
    1426           0 :                 return !f_node_set.isEmpty();
    1427             : 
    1428           0 :             default:
    1429           0 :                 break;
    1430             : 
    1431             :             }
    1432             :         }
    1433           0 :         return atomic_value_t::getBooleanValue(cast);
    1434             :     }
    1435             : 
    1436             :     /** \brief Retrieve the Integer value.
    1437             :      *
    1438             :      * This function retrieves the Integer value from the variant. If
    1439             :      * the \p cast parameter is true, then the sets are also checked
    1440             :      * and return the first value if they are not empty.
    1441             :      *
    1442             :      * \todo
    1443             :      * See how it should be handled in XPath 2.x because it is different
    1444             :      * than in XPath 1.x.
    1445             :      *
    1446             :      * \param[in] cast  Whether to cast the value if not an Integer.
    1447             :      *
    1448             :      * \return The Integer value or whatever value converted to an Integer.
    1449             :      */
    1450           0 :     int64_t getIntegerValue(bool cast = false) const
    1451             :     {
    1452           0 :         if(cast)
    1453             :         {
    1454           0 :             switch(f_type)
    1455             :             {
    1456           0 :             case type_t::ATOMIC_TYPE_SET:
    1457             :                 // TODO -- do proper implementation
    1458           0 :                 return static_cast<int64_t>(!f_set.isEmpty());
    1459             : 
    1460           0 :             case type_t::ATOMIC_TYPE_NODE_SET:
    1461             :                 // TODO -- do proper implementation
    1462           0 :                 return static_cast<int64_t>(!f_node_set.isEmpty());
    1463             : 
    1464           0 :             default:
    1465           0 :                 break;
    1466             : 
    1467             :             }
    1468             :         }
    1469           0 :         return atomic_value_t::getIntegerValue(cast);
    1470             :     }
    1471             : 
    1472             :     /** \brief Retrieve the single value.
    1473             :      *
    1474             :      * This function retrieves the single value from the variant. If
    1475             :      * the \p cast parameter is true, then the sets are also checked
    1476             :      * and return the first value if they are not empty.
    1477             :      *
    1478             :      * \todo
    1479             :      * See how it should be handled in XPath 2.x because it is different
    1480             :      * than in XPath 1.x.
    1481             :      *
    1482             :      * \param[in] cast  Whether to cast the value if not a Single.
    1483             :      *
    1484             :      * \return The Single value, or the converted value of another type.
    1485             :      */
    1486           0 :     float getSingleValue(bool cast = false) const
    1487             :     {
    1488           0 :         if(cast)
    1489             :         {
    1490           0 :             switch(f_type)
    1491             :             {
    1492           0 :             case type_t::ATOMIC_TYPE_SET:
    1493             :                 // TODO -- do proper implementation
    1494           0 :                 return static_cast<float>(!f_set.isEmpty());
    1495             : 
    1496           0 :             case type_t::ATOMIC_TYPE_NODE_SET:
    1497             :                 // TODO -- do proper implementation
    1498           0 :                 return static_cast<float>(!f_node_set.isEmpty());
    1499             : 
    1500           0 :             default:
    1501           0 :                 break;
    1502             : 
    1503             :             }
    1504             :         }
    1505           0 :         return atomic_value_t::getSingleValue(cast);
    1506             :     }
    1507             : 
    1508             :     /** \brief Retrieve the double value.
    1509             :      *
    1510             :      * This function retrieves the double value from the variant. If
    1511             :      * the \p cast parameter is true, then the sets are also checked
    1512             :      * and return the first value if they are not empty.
    1513             :      *
    1514             :      * \todo
    1515             :      * See how it should be handled in XPath 2.x because it is different
    1516             :      * than in XPath 1.x.
    1517             :      *
    1518             :      * \param[in] cast  Whether to cast the value if not a Double.
    1519             :      *
    1520             :      * \return The Double value, or the converted value if not Double.
    1521             :      */
    1522           0 :     double getDoubleValue(bool cast = false) const
    1523             :     {
    1524           0 :         if(cast)
    1525             :         {
    1526           0 :             switch(f_type)
    1527             :             {
    1528           0 :             case type_t::ATOMIC_TYPE_SET:
    1529             :                 // TODO -- do proper implementation
    1530           0 :                 return static_cast<double>(!f_set.isEmpty());
    1531             : 
    1532           0 :             case type_t::ATOMIC_TYPE_NODE_SET:
    1533             :             {
    1534           0 :                 QString str(getStringValue(true));
    1535             :                 // TODO -- do proper string to double implementation
    1536           0 :                 return atof(str.toUtf8().data());
    1537             :             }
    1538             : 
    1539           0 :             default:
    1540           0 :                 break;
    1541             : 
    1542             :             }
    1543             :         }
    1544           0 :         return atomic_value_t::getDoubleValue(cast);
    1545             :     }
    1546             : 
    1547             :     /** \brief Retrieve the string value.
    1548             :      *
    1549             :      * This function retrieves the string value from the variant. If
    1550             :      * the \p cast parameter is true, then the sets are also checked.
    1551             :      *
    1552             :      * An atomic set is transformed in a list of atomic values written
    1553             :      * between parenthesis and separated by commas.
    1554             :      *
    1555             :      * In case of a node-set, only the first node (in document order) is
    1556             :      * transformed to a string with the DOM toString() function (maybe with
    1557             :      * -1 as the indent parameter to avoid having spaces added by the DOM
    1558             :      * output functions.) The content returned depends on the type of node:
    1559             :      *
    1560             :      * \li Document Node -- all the child text nodes.
    1561             :      * \li Element -- all the child text nodes.
    1562             :      * \li Namespace Node -- the URI property.
    1563             :      * \li Attribute -- the attribute value.
    1564             :      * \li Comment -- the comment value.
    1565             :      * \li Processing Instruction -- the text between the \<? and ?\>
    1566             :      * \li Text Node -- the text of the node
    1567             :      *
    1568             :      * \todo
    1569             :      * See how it should be handled in XPath 2.x because it is different
    1570             :      * than in XPath 1.x.
    1571             :      *
    1572             :      * Some information about casting a node-set to a string can be found in:
    1573             :      *
    1574             :      * http://saxon.sourceforge.net/saxon6.5.3/expressions.html
    1575             :      *
    1576             :      * \param[in] cast  Whether to cast the value if not a Double.
    1577             :      *
    1578             :      * \return The Double value, or the converted value if not Double.
    1579             :      */
    1580           0 :     QString getStringValue(bool cast = false) const
    1581             :     {
    1582           0 :         if(cast)
    1583             :         {
    1584           0 :             switch(f_type)
    1585             :             {
    1586           0 :             case type_t::ATOMIC_TYPE_SET:
    1587             :                 // TODO -- do proper implementation
    1588           0 :                 throw QDomXPathException_NotImplemented("cast(atomic set) as string is not implemented");
    1589             : 
    1590           0 :             case type_t::ATOMIC_TYPE_NODE_SET:
    1591           0 :                 if(f_node_set.isEmpty())
    1592             :                 {
    1593             :                     // no nodes, return an empty string
    1594           0 :                     return "";
    1595             :                 }
    1596           0 :                 return node_to_string(f_node_set[0]);
    1597             : 
    1598           0 :             default:
    1599           0 :                 break;
    1600             : 
    1601             :             }
    1602             :         }
    1603           0 :         return atomic_value_t::getStringValue(cast);
    1604             :     }
    1605             : 
    1606           0 :     static QString node_to_string(const QDomNode& node)
    1607             :     {
    1608           0 :         switch(node.nodeType())
    1609             :         {
    1610           0 :         case QDomNode::ElementNode:
    1611             :             // return all the text nodes from all the children
    1612           0 :             return node.toElement().text();
    1613             : 
    1614           0 :         case QDomNode::AttributeNode:
    1615             :             // return the corresponding value
    1616           0 :             return node.toAttr().value();
    1617             : 
    1618           0 :         case QDomNode::TextNode:
    1619           0 :             return node.toText().data();
    1620             : 
    1621           0 :         case QDomNode::CDATASectionNode:
    1622           0 :             return node.toCDATASection().data();
    1623             : 
    1624           0 :         case QDomNode::ProcessingInstructionNode:
    1625           0 :             return node.toProcessingInstruction().data();
    1626             : 
    1627           0 :         case QDomNode::CommentNode:
    1628           0 :             return node.toComment().data();
    1629             : 
    1630           0 :         case QDomNode::DocumentNode:
    1631             :             {
    1632           0 :                 QDomDocument document(node.toDocument());
    1633           0 :                 QDomElement element(document.documentElement());
    1634           0 :                 if(element.isNull())
    1635             :                 {
    1636           0 :                     return "";
    1637             :                 }
    1638           0 :                 return element.text();
    1639             :             }
    1640             : 
    1641           0 :         case QDomNode::CharacterDataNode:
    1642           0 :             return node.toCharacterData().data();
    1643             : 
    1644             :         //case QDomNode::BaseNode:
    1645             :         //case QDomNode::DocumentTypeNode:
    1646             :         //case QDomNode::DocumentFragmentNode:
    1647             :         //case QDomNode::EntityReferenceNode:
    1648             :         //case QDomNode::EntityNode:
    1649             :         //case QDomNode::NotationNode:
    1650           0 :         default:
    1651           0 :             throw QDomXPathException_NotImplemented(QString("cast(node) as string for this node type (%1) is not implemented")
    1652           0 :                                                             .arg(static_cast<int>(node.nodeType())));
    1653             : 
    1654             :         }
    1655             :         /*NOTREACHED*/
    1656             :     }
    1657             : 
    1658             :     /** \brief Retrieve the set value.
    1659             :      *
    1660             :      * This function retrieves the set value from the variant. If
    1661             :      * the \p cast parameter is true, then any other value is returned
    1662             :      * as a set composed of that value (in case of NULL, an empty set.)
    1663             :      *
    1664             :      * \param[in] cast  Whether to cast the value if not a Set.
    1665             :      *
    1666             :      * \return A set of atomic values.
    1667             :      */
    1668           0 :     atomic_vector_t getSetValue(bool cast = false) const
    1669             :     {
    1670           0 :         if(f_type != type_t::ATOMIC_TYPE_SET)
    1671             :         {
    1672           0 :             if(!cast)
    1673             :             {
    1674           0 :                 throw QDomXPathException_WrongType(QString("atomic type is %1, when a Set was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1675             :             }
    1676             :         }
    1677           0 :         atomic_vector_t result;
    1678           0 :         switch(f_type)
    1679             :         {
    1680           0 :         case type_t::ATOMIC_TYPE_NULL:
    1681           0 :             return result; // empty set
    1682             : 
    1683           0 :         case type_t::ATOMIC_TYPE_BOOLEAN:
    1684             :         case type_t::ATOMIC_TYPE_INTEGER:
    1685             :         case type_t::ATOMIC_TYPE_SINGLE:
    1686             :         case type_t::ATOMIC_TYPE_DOUBLE:
    1687             :         case type_t::ATOMIC_TYPE_STRING:
    1688           0 :             result.push_back(*this);
    1689           0 :             return result;
    1690             : 
    1691           0 :         case type_t::ATOMIC_TYPE_SET:
    1692           0 :             return f_set;
    1693             : 
    1694           0 :         case type_t::ATOMIC_TYPE_NODE_SET: // TODO -- is that an error or should we return something like the string() of each node
    1695             :         default:
    1696           0 :             throw QDomXPathException_NotImplemented(QString("type %1 to set conversion is not implemented").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1697             : 
    1698             :         }
    1699             :     }
    1700             : 
    1701             :     /** \brief Set the variant to a set of atomic values.
    1702             :      *
    1703             :      * In XPath version 2.0 sets of atomic values were added to the XPath
    1704             :      * specification. For example, a set of all multiple of 5 between 0
    1705             :      * and 100 inclusive are defined as:
    1706             :      *
    1707             :      * \code
    1708             :      * (0 to 100)[. mod 5 = 0]
    1709             :      * \endcode
    1710             :      *
    1711             :      * \param[in] set  The set to become the variant atomic set.
    1712             :      */
    1713           0 :     void setValue(atomic_vector_t const& set)
    1714             :     {
    1715           0 :         f_type = type_t::ATOMIC_TYPE_SET;
    1716           0 :         f_set = set;
    1717           0 :     }
    1718             : 
    1719             : 
    1720             :     /** \brief Retrieve the node set value.
    1721             :      *
    1722             :      * This function retrieves the node set value from the variant.
    1723             :      *
    1724             :      * If the variant is not a node set then an error is generated
    1725             :      * (there is no way really to convert an atomic type to a set
    1726             :      * of nodes.)
    1727             :      *
    1728             :      * \param[in] cast  Ignored.
    1729             :      *
    1730             :      * \return The node set.
    1731             :      */
    1732             : #pragma GCC diagnostic push
    1733             : #pragma GCC diagnostic ignored "-Wunused-parameter"
    1734           0 :     QDomXPath::node_vector_t& getNodeSetValue(bool cast = false) const
    1735             :     {
    1736           0 :         if(f_type != type_t::ATOMIC_TYPE_NODE_SET)
    1737             :         {
    1738           0 :             throw QDomXPathException_WrongType(QString("atomic type is %1, when a Node Set was requested").arg(static_cast<int>(static_cast<type_t>(f_type))));
    1739             :         }
    1740           0 :         return const_cast<QDomXPath::node_vector_t&>(f_node_set);
    1741             :     }
    1742             : #pragma GCC diagnostic pop
    1743             : 
    1744             : 
    1745             :     /** \brief Set the variant to a node set.
    1746             :      *
    1747             :      * This function sets the variant to the specified \p node_set.
    1748             :      *
    1749             :      * The input value is copied, although remember that in a DOM all
    1750             :      * the object we have access to are references and changing the
    1751             :      * DOM will affect the nodes wherever they are.
    1752             :      *
    1753             :      * \param[in] node_set  The node set to save in this variant.
    1754             :      */
    1755           0 :     void setValue(const QDomXPath::node_vector_t& node_set)
    1756             :     {
    1757           0 :         f_type = type_t::ATOMIC_TYPE_NODE_SET;
    1758           0 :         f_node_set = node_set;
    1759           0 :     }
    1760             : 
    1761             : 
    1762             :     /** \brief Retrieve the context value.
    1763             :      *
    1764             :      * This function retrieves the context value from the variant.
    1765             :      *
    1766             :      * If the variant is not a context then an error is generated.
    1767             :      * Contexts should only be used in very specific places which do
    1768             :      * not call for casting. If an error occurs then there is an
    1769             :      * internal error.
    1770             :      *
    1771             :      * \param[in] cast  Ignored.
    1772             :      *
    1773             :      * \return The context.
    1774             :      */
    1775             :     //context_t& getContextValue(bool cast = false) const
    1776             :     //{
    1777             :     //    if(f_type != type_t::ATOMIC_TYPE_CONTEXT)
    1778             :     //    {
    1779             :     //        throw QDomXPathException_WrongType(QString("atomic type is %1, when a Context was requested").arg(static_cast<int>(f_type)));
    1780             :     //    }
    1781             :     //    return const_cast<context_t&>(f_context);
    1782             :     //}
    1783             : 
    1784             : 
    1785             :     /** \brief Set the variant to a context.
    1786             :      *
    1787             :      * This function sets the variant to the specified \p context.
    1788             :      *
    1789             :      * The input value is copied, although remember that in a DOM all
    1790             :      * the object we have access to are references and changing the
    1791             :      * DOM will affect the nodes wherever they are.
    1792             :      *
    1793             :      * \param[in] context  The context to save in this variant.
    1794             :      */
    1795             :     //void setValue(const context_t& context)
    1796             :     //{
    1797             :     //    f_type = type_t::ATOMIC_TYPE_CONTEXT;
    1798             :     //    f_context = context;
    1799             :     //}
    1800             : 
    1801             : private:
    1802             :     atomic_vector_t             f_set = atomic_vector_t();      // set of atomic values
    1803             :     QDomXPath::node_vector_t    f_node_set = QDomXPath::node_vector_t(); // set of nodes -- use the node vector in the context to save space
    1804             :     //context_t                   f_context;  // the current context
    1805             : };
    1806             : 
    1807             : 
    1808             : /** \brief An array of variants.
    1809             :  *
    1810             :  * The array of variants is especially useful as a function stack.
    1811             :  */
    1812             : typedef QVector<variant_t>  variant_vector_t;
    1813             : 
    1814             : 
    1815             : /** \brief Current function being run.
    1816             :  *
    1817             :  * While running we may call functions. For that purpose we need to have
    1818             :  * a function class because the current state of the current function
    1819             :  * cannot be touched while a child function is running. Similarly, the
    1820             :  * stack of the child should not affect the stack of the caller. This is
    1821             :  * the easiest way to protect those stacks and have an easy way to
    1822             :  * apply the INST_RETURN instruction.
    1823             :  */
    1824           0 : struct function_t
    1825             : {
    1826             :     typedef QMap<QString, variant_t> variables_t;
    1827             : 
    1828             :     uint32_t                f_pc = 0;
    1829             :     variant_vector_t        f_stack = variant_vector_t();
    1830             :     context_vector_t        f_contexts = context_vector_t();
    1831             :     variables_t             f_variables = variables_t();
    1832             : };
    1833             : 
    1834             : 
    1835             : /** \brief An array of function status.
    1836             :  *
    1837             :  * This array holds a set of function_t structures, each representing a
    1838             :  * function environment. When a function calls another, a new function_t
    1839             :  * is created at the back of the stack of function environment.
    1840             :  *
    1841             :  * The program as a whole has one stack of functions.
    1842             :  *
    1843             :  * The first function (i.e. front) represents the main program and it
    1844             :  * is not removed with a return, instead the program ends on a return.
    1845             :  */
    1846             : typedef QVector<function_t> function_vector_t;
    1847             : 
    1848             : 
    1849             : /** \brief List of internal functions.
    1850             :  *
    1851             :  * This enumeration defines a list of internal functions which are called
    1852             :  * using the INST_CALL basic instruction.
    1853             :  *
    1854             :  * Note that some internal functions are transformed at compile time to
    1855             :  * work just like a simple push or some other basic instruction.
    1856             :  */
    1857             : enum class internal_func_t
    1858             : {
    1859             :     FUNC_UNKNOWN,
    1860             :     FUNC_AVG,
    1861             :     FUNC_MIN,
    1862             :     FUNC_MAX,
    1863             :     FUNC_SUM
    1864             : };
    1865             : 
    1866             : 
    1867             : /** \brief All the instructions are parameter less functions.
    1868             :  *
    1869             :  * Instructions have full access to the QDomXPathImpl class so it is
    1870             :  * parameter less and they return void.
    1871             :  *
    1872             :  * If an internal error is detected, then the corresponding internal
    1873             :  * error exception is thrown.
    1874             :  *
    1875             :  * Otherwise instructions do not really generate errors at this point.
    1876             :  * In version 2.0 of XPath we are expected to generate errors if a
    1877             :  * parameter type is incorrect (i.e. you pass a string to a function
    1878             :  * that expects an integer). That will be added later.
    1879             :  */
    1880             : typedef void (QDomXPathImpl::*instruction_function_t)();
    1881             : 
    1882             : /** \brief The array of instructions.
    1883             :  *
    1884             :  * This array definition is used to declare all the instructions.
    1885             :  * Because of the way the compiler functions, the array itself is
    1886             :  * initialized outside of the class (search on g_instructions to
    1887             :  * find it.)
    1888             :  *
    1889             :  * Since instructions are defined on one byte, all the entries (256)
    1890             :  * are defined. Instructions that are undefined call the default
    1891             :  * inst_undefined_instruction() function which throws the
    1892             :  * QDomXPathException_UndefinedInstructionError exception.
    1893             :  */
    1894             : static instruction_function_t const g_instructions[256];
    1895             : 
    1896             : /** \brief Function to disassemble instructions.
    1897             :  *
    1898             :  * Each one of these functions print the given instruction that looks like
    1899             :  * assembly language code. The function returns the size of the instruction.
    1900             :  * It is passed the PC just after the instruction.
    1901             :  */
    1902             : typedef uint32_t (QDomXPathImpl::*disassembly_function_t)(uint32_t pc);
    1903             : 
    1904             : /** \brief The array of disassembling functions.
    1905             :  *
    1906             :  * This array definition is used to print out the different instructions
    1907             :  * either as they are executed or as they are compiled.
    1908             :  */
    1909             : static disassembly_function_t const g_disassemble_instructions[256];
    1910             : 
    1911             : 
    1912             : static const QDomXPath::instruction_t      INST_END                        = 0x00;
    1913             : static const QDomXPath::instruction_t      INST_CALL                       = 0x01;
    1914             : static const QDomXPath::instruction_t      INST_SMALL_FUNCTION             = 0x02;
    1915             : static const QDomXPath::instruction_t      INST_LARGE_FUNCTION             = 0x03;
    1916             : static const QDomXPath::instruction_t      INST_JUMP                       = 0x04;
    1917             : static const QDomXPath::instruction_t      INST_JUMP_IF_TRUE               = 0x05;
    1918             : static const QDomXPath::instruction_t      INST_JUMP_IF_FALSE              = 0x06;
    1919             : static const QDomXPath::instruction_t      INST_JUMP_IF_ZERO               = 0x07;
    1920             : static const QDomXPath::instruction_t      INST_RETURN                     = 0x08;
    1921             : 
    1922             : static const QDomXPath::instruction_t      INST_GET_VARIABLE               = 0x10;
    1923             : static const QDomXPath::instruction_t      INST_SET_VARIABLE               = 0x11;
    1924             : 
    1925             : static const QDomXPath::instruction_t      INST_POP1                       = 0x20;
    1926             : static const QDomXPath::instruction_t      INST_POP2                       = 0x21;
    1927             : static const QDomXPath::instruction_t      INST_POP3                       = 0x22;
    1928             : static const QDomXPath::instruction_t      INST_POP4                       = 0x23;
    1929             : static const QDomXPath::instruction_t      INST_POP5                       = 0x24;
    1930             : 
    1931             : static const QDomXPath::instruction_t      INST_DUPLICATE1                 = 0x2A;
    1932             : static const QDomXPath::instruction_t      INST_DUPLICATE2                 = 0x2B;
    1933             : static const QDomXPath::instruction_t      INST_DUPLICATE3                 = 0x2C;
    1934             : static const QDomXPath::instruction_t      INST_DUPLICATE4                 = 0x2D;
    1935             : static const QDomXPath::instruction_t      INST_DUPLICATE5                 = 0x2E;
    1936             : 
    1937             : static const QDomXPath::instruction_t      INST_SWAP1                      = 0x30;
    1938             : static const QDomXPath::instruction_t      INST_SWAP2                      = 0x31;
    1939             : static const QDomXPath::instruction_t      INST_SWAP3                      = 0x32;
    1940             : static const QDomXPath::instruction_t      INST_SWAP4                      = 0x33;
    1941             : static const QDomXPath::instruction_t      INST_SWAP5                      = 0x34;
    1942             : static const QDomXPath::instruction_t      INST_SWAP2_3                    = 0x35;
    1943             : 
    1944             : static const QDomXPath::instruction_t      INST_PUSH_ANY_STRING            = 0x40;
    1945             : static const QDomXPath::instruction_t      INST_PUSH_BYTE                  = 0x41;
    1946             : static const QDomXPath::instruction_t      INST_PUSH_DOUBLE                = 0x42;
    1947             : static const QDomXPath::instruction_t      INST_PUSH_DOUBLE_ZERO           = 0x43;
    1948             : static const QDomXPath::instruction_t      INST_PUSH_EMPTY_NODE_SET        = 0x44;
    1949             : static const QDomXPath::instruction_t      INST_PUSH_EMPTY_SET             = 0x45;
    1950             : static const QDomXPath::instruction_t      INST_PUSH_EMPTY_STRING          = 0x46;
    1951             : static const QDomXPath::instruction_t      INST_PUSH_END_OF_ARGUMENTS      = 0x47;
    1952             : static const QDomXPath::instruction_t      INST_PUSH_FALSE                 = 0x48;
    1953             : static const QDomXPath::instruction_t      INST_PUSH_LARGE_STRING          = 0x49;
    1954             : static const QDomXPath::instruction_t      INST_PUSH_LONG                  = 0x4A;
    1955             : static const QDomXPath::instruction_t      INST_PUSH_LONGLONG              = 0x4B;
    1956             : static const QDomXPath::instruction_t      INST_PUSH_MEDIUM_STRING         = 0x4C;
    1957             : static const QDomXPath::instruction_t      INST_PUSH_NEGATIVE_BYTE         = 0x4D;
    1958             : static const QDomXPath::instruction_t      INST_PUSH_NEGATIVE_SHORT        = 0x4E;
    1959             : static const QDomXPath::instruction_t      INST_PUSH_NEGATIVE_LONG         = 0x4F;
    1960             : static const QDomXPath::instruction_t      INST_PUSH_SHORT                 = 0x50;
    1961             : static const QDomXPath::instruction_t      INST_PUSH_SMALL_STRING          = 0x51;
    1962             : static const QDomXPath::instruction_t      INST_PUSH_TRUE                  = 0x52;
    1963             : static const QDomXPath::instruction_t      INST_PUSH_ZERO                  = 0x53;
    1964             : 
    1965             : static const QDomXPath::instruction_t      INST_ADD                        = 0x60;
    1966             : static const QDomXPath::instruction_t      INST_AND                        = 0x61;
    1967             : static const QDomXPath::instruction_t      INST_CEILING                    = 0x62;
    1968             : static const QDomXPath::instruction_t      INST_DECREMENT                  = 0x63;
    1969             : static const QDomXPath::instruction_t      INST_DIVIDE                     = 0x64;
    1970             : static const QDomXPath::instruction_t      INST_EQUAL                      = 0x65;
    1971             : static const QDomXPath::instruction_t      INST_FLOOR                      = 0x66;
    1972             : static const QDomXPath::instruction_t      INST_GREATER_OR_EQUAL           = 0x67;
    1973             : static const QDomXPath::instruction_t      INST_GREATER_THAN               = 0x68;
    1974             : static const QDomXPath::instruction_t      INST_IDIVIDE                    = 0x69;
    1975             : static const QDomXPath::instruction_t      INST_INCREMENT                  = 0x6A;
    1976             : static const QDomXPath::instruction_t      INST_LESS_OR_EQUAL              = 0x6B;
    1977             : static const QDomXPath::instruction_t      INST_LESS_THAN                  = 0x6C;
    1978             : static const QDomXPath::instruction_t      INST_MODULO                     = 0x6D;
    1979             : static const QDomXPath::instruction_t      INST_MULTIPLY                   = 0x6E;
    1980             : static const QDomXPath::instruction_t      INST_NEGATE                     = 0x6F;
    1981             : static const QDomXPath::instruction_t      INST_NOT                        = 0x70;
    1982             : static const QDomXPath::instruction_t      INST_NOT_EQUAL                  = 0x71;
    1983             : static const QDomXPath::instruction_t      INST_OR                         = 0x72;
    1984             : static const QDomXPath::instruction_t      INST_ROUND                      = 0x73;
    1985             : static const QDomXPath::instruction_t      INST_STRING_LENGTH              = 0x74;
    1986             : static const QDomXPath::instruction_t      INST_SUBTRACT                   = 0x75;
    1987             : 
    1988             : static const QDomXPath::instruction_t      INST_AXIS                       = 0x80;
    1989             : static const QDomXPath::instruction_t      INST_ROOT                       = 0x81;
    1990             : static const QDomXPath::instruction_t      INST_GET_NODE_SET               = 0x82;
    1991             : static const QDomXPath::instruction_t      INST_SET_NODE_SET               = 0x83;
    1992             : static const QDomXPath::instruction_t      INST_GET_RESULT                 = 0x84;
    1993             : static const QDomXPath::instruction_t      INST_SET_RESULT                 = 0x85;
    1994             : static const QDomXPath::instruction_t      INST_GET_POSITION               = 0x86;
    1995             : static const QDomXPath::instruction_t      INST_SET_POSITION               = 0x87;
    1996             : static const QDomXPath::instruction_t      INST_NODE_SET_SIZE              = 0x88;
    1997             : static const QDomXPath::instruction_t      INST_MERGE_SETS                 = 0x89;
    1998             : static const QDomXPath::instruction_t      INST_PREDICATE                  = 0x8A;
    1999             : static const QDomXPath::instruction_t      INST_CREATE_NODE_CONTEXT        = 0x8B;
    2000             : static const QDomXPath::instruction_t      INST_GET_CONTEXT_NODE           = 0x8C;
    2001             : static const QDomXPath::instruction_t      INST_NEXT_CONTEXT_NODE          = 0x8D;
    2002             : static const QDomXPath::instruction_t      INST_POP_CONTEXT                = 0x8E;
    2003             : 
    2004             : 
    2005             : enum class axis_t
    2006             : {
    2007             :     AXIS_ANCESTOR,
    2008             :     AXIS_ANCESTOR_OR_SELF,
    2009             :     AXIS_ATTRIBUTE,
    2010             :     AXIS_CHILD,
    2011             :     AXIS_DESCENDANT,
    2012             :     AXIS_DESCENDANT_OR_SELF,
    2013             :     AXIS_FOLLOWING,
    2014             :     AXIS_FOLLOWING_SIBLING,
    2015             :     AXIS_NAMESPACE,
    2016             :     AXIS_PARENT,
    2017             :     AXIS_PRECEDING,
    2018             :     AXIS_PRECEDING_SIBLING,
    2019             :     AXIS_SELF
    2020             : };
    2021             : 
    2022             : enum class node_type_t
    2023             : {
    2024             :     // XPath 1.0
    2025             :     NODE_TYPE_COMMENT,
    2026             :     NODE_TYPE_NODE,
    2027             :     NODE_TYPE_PROCESSING_INSTRUCTION,
    2028             :     NODE_TYPE_TEXT,
    2029             : 
    2030             :     // XPath 2.0 (not supported yet)
    2031             :     NODE_TYPE_DOCUMENT_NODE,
    2032             :     NODE_TYPE_ELEMENT,
    2033             :     NODE_TYPE_SCHEMA_ELEMENT,
    2034             :     NODE_TYPE_ATTRIBUTE,
    2035             :     NODE_TYPE_SCHEMA_ATTRIBUTE
    2036             : };
    2037             : 
    2038             : 
    2039             : /** \brief Initialize the class.
    2040             :  *
    2041             :  * This function initializes the class. Once the constructor returns
    2042             :  * the object parse() function can be called in order to get the
    2043             :  * XPath transformed to tokens and ready to be applied against nodes.
    2044             :  *
    2045             :  * The function also initializes the program header as defined in the
    2046             :  * QDomXPath::getProgram().
    2047             :  *
    2048             :  * \param[in] owner  The QDomXPath, the owner or parent of this QDomXPathImpl
    2049             :  * \param[in] xpath  The XPath to be compiled; may be "" when used only to execute a program
    2050             :  */
    2051           0 : QDomXPathImpl(QDomXPath *owner, const QString& xpath)
    2052           0 :     : f_owner(owner)
    2053             :     , f_xpath(xpath)
    2054           0 :     , f_start(f_xpath.data())
    2055           0 :     , f_in(f_start)
    2056             : {
    2057           0 :     f_program.push_back(QDomXPath::MAGIC[0]);
    2058           0 :     f_program.push_back(QDomXPath::MAGIC[1]);
    2059           0 :     f_program.push_back(QDomXPath::MAGIC[2]);
    2060           0 :     f_program.push_back(QDomXPath::MAGIC[3]);
    2061           0 :     f_program.push_back(VERSION_MAJOR);
    2062           0 :     f_program.push_back(VERSION_MINOR);
    2063           0 :     std::string str(xpath.toUtf8().data());
    2064           0 :     size_t size(str.length());
    2065           0 :     if(size > 65535)
    2066             :     {
    2067           0 :         size = 65535;
    2068             :     }
    2069           0 :     f_program.push_back(static_cast<instruction_t>(size >> 8));
    2070           0 :     f_program.push_back(static_cast<instruction_t>(size));
    2071           0 :     for(size_t i(0); i < size; ++i)
    2072             :     {
    2073           0 :         f_program.push_back(str[i]);
    2074             :     }
    2075           0 :     f_program_start_offset = f_program.size();
    2076           0 : }
    2077             : 
    2078             : 
    2079             : QDomXPathImpl(QDomXPathImpl const & rhs) = delete;
    2080             : QDomXPathImpl & operator = (QDomXPathImpl const & rhs) = delete;
    2081             : 
    2082             : 
    2083             : /** \brief While executing, read a byte.
    2084             :  *
    2085             :  * There are two sets of instructions that get data from the program area:
    2086             :  *
    2087             :  * \li The push instructions that converts the data to a variant value
    2088             :  *     and push that on the stack.
    2089             :  *
    2090             :  * \li The program execution environment which reads one byte instruction
    2091             :  *     and executes the corresponding function.
    2092             :  *
    2093             :  * \return The following 1 byte.
    2094             :  */
    2095           0 : int get_next_program_byte()
    2096             : {
    2097           0 :     if(f_functions.back().f_pc >= static_cast<uint32_t>(f_program.size()))
    2098             :     {
    2099           0 :         throw QDomXPathException_InternalError("trying to read more bytes from f_program than available");
    2100             :     }
    2101           0 :     int result(f_program[f_functions.back().f_pc]);
    2102           0 :     ++f_functions.back().f_pc;
    2103           0 :     return result;
    2104             : }
    2105             : 
    2106             : 
    2107             : /** \brief Verify that the stack is not empty.
    2108             :  *
    2109             :  * This function checks the stack, if empty, it throws an internal error
    2110             :  * as this should never happend.
    2111             :  *
    2112             :  * By default the type of the variant at the top of the stack is not checked.
    2113             :  * By setting the \p type parameter to something else than
    2114             :  * type_t::ATOMIC_TYPE_UNDEFINED, the function enforces that type for the object
    2115             :  * at the top of the stack.
    2116             :  *
    2117             :  * \param[in] type  The type of the variant on the top of the stack.
    2118             :  *                  Ignore if set to type_t::ATOMIC_TYPE_UNDEFINED.
    2119             :  */
    2120           0 : void stack_not_empty(atomic_value_t::type_t type = atomic_value_t::type_t::ATOMIC_TYPE_UNDEFINED)
    2121             : {
    2122           0 :     if(f_functions.back().f_stack.empty())
    2123             :     {
    2124           0 :         throw QDomXPathException_InternalError("cannot pop anything from an empty stack");
    2125             :     }
    2126           0 :     if(type != atomic_value_t::type_t::ATOMIC_TYPE_UNDEFINED
    2127           0 :     && f_functions.back().f_stack.back().getType() != type)
    2128             :     {
    2129           0 :         throw QDomXPathException_WrongType(QString("the current type at the top of the stack is not of the right type (expected %1, it is %2)")
    2130           0 :                                             .arg(static_cast<int>(type))
    2131           0 :                                             .arg(static_cast<int>(f_functions.back().f_stack.back().getType())));
    2132             :     }
    2133           0 : }
    2134             : 
    2135             : 
    2136             : /** \brief Check that the stack of contexts is not empty.
    2137             :  *
    2138             :  * The stack of contexts is created by the INST_CREATE_NODE_CONTEXT
    2139             :  * instruction. It should never be used if empty so we have this
    2140             :  * function to check the validity in one place.
    2141             :  */
    2142           0 : void contexts_not_empty()
    2143             : {
    2144           0 :     if(f_functions.back().f_contexts.empty())
    2145             :     {
    2146           0 :         throw QDomXPathException_InternalError("cannot pop anything from an empty stack of contexts");
    2147             :     }
    2148           0 : }
    2149             : 
    2150             : 
    2151             : /** \brief Pop one entry from the stack.
    2152             :  *
    2153             :  * This function checks the stack, if empty, it throws an internal error
    2154             :  * as this should never happend.
    2155             :  *
    2156             :  * \return A variant with the data from the top of the stack.
    2157             :  */
    2158           0 : variant_t pop_variant_data()
    2159             : {
    2160           0 :     stack_not_empty();
    2161             : 
    2162             : #if 0
    2163             :     printf("Stack Trace:\n");
    2164             :     for(int i(0); i < f_functions.back().f_stack.size(); ++i)
    2165             :     {
    2166             :         variant_t v(f_functions.back().f_stack[i]);
    2167             :         switch(v.getType())
    2168             :         {
    2169             :         case atomic_value_t::type_t::ATOMIC_TYPE_UNDEFINED:
    2170             :             printf(" + Undefined\n");
    2171             :             break;
    2172             : 
    2173             :         case atomic_value_t::type_t::ATOMIC_TYPE_NULL:
    2174             :             printf(" + NULL\n");
    2175             :             break;
    2176             : 
    2177             :         case atomic_value_t::type_t::ATOMIC_TYPE_END_OF_ARGUMENTS:
    2178             :             printf(" + End of Arguments\n");
    2179             :             break;
    2180             : 
    2181             :         case atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN:
    2182             :             printf(" + Boolean (%s)\n", (v.getBooleanValue() ? "true" : "false"));
    2183             :             break;
    2184             : 
    2185             :         case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    2186             :             printf(" + Integer (%ld)\n", v.getIntegerValue());
    2187             :             break;
    2188             : 
    2189             :         //case atomic_value_t::type_t::ATOMIC_TYPE_DECIMAL:
    2190             :         case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    2191             :             printf(" + Single (%g)\n", v.getSingleValue());
    2192             :             break;
    2193             : 
    2194             :         case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    2195             :             printf(" + Double (%g)\n", v.getDoubleValue());
    2196             :             break;
    2197             : 
    2198             :         case atomic_value_t::type_t::ATOMIC_TYPE_STRING:
    2199             :             printf(" + String (\"%s\")\n", v.getStringValue().toUtf8().data());
    2200             :             break;
    2201             : 
    2202             :         case atomic_value_t::type_t::ATOMIC_TYPE_SET:
    2203             :             printf(" + Atomic Set\n");
    2204             :             break;
    2205             : 
    2206             :         case atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET:
    2207             :             printf(" + Node Set\n");
    2208             :             break;
    2209             : 
    2210             :         }
    2211             :     }
    2212             : #endif
    2213             : 
    2214           0 :     variant_t v(f_functions.back().f_stack.back());
    2215           0 :     f_functions.back().f_stack.pop_back();
    2216             : 
    2217           0 :     return v;
    2218             : }
    2219             : 
    2220             : 
    2221             : /** \brief For all undefined instructions.
    2222             :  *
    2223             :  * This function is used by all the undefined instructions so we can always
    2224             :  * run something (i.e. instead of using NULL) and avoid testing the pointers.
    2225             :  *
    2226             :  * This function always raises the QDomXPathException_UndefinedInstructionError
    2227             :  * exception.
    2228             :  */
    2229           0 : void inst_undefined_instruction()
    2230             : {
    2231           0 :     QDomXPath::instruction_t inst(f_program[f_functions.back().f_pc - 1]);
    2232           0 :     throw QDomXPathException_UndefinedInstructionError(QString("instruction %1 is not defined (pc = %2)")
    2233           0 :             .arg(static_cast<int>(inst)).arg(f_functions.back().f_pc - 1));
    2234             : }
    2235             : 
    2236             : 
    2237             : /** \brief The End instruction.
    2238             :  *
    2239             :  * This function raises an exception because it should never be executed.
    2240             :  * Instead the function running the execution loop is expected to catch this
    2241             :  * special case and return. However, just in case it were to be executed,
    2242             :  * we have a function that throws.
    2243             :  */
    2244           0 : void inst_end()
    2245             : {
    2246             : #if QDOM_XPATH_VERIFICATION
    2247             :     // verify instruction location
    2248           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_END)
    2249             :     {
    2250           0 :         throw QDomXPathException_InternalError("INST_END not at the right location in the table of instructions");
    2251             :     }
    2252             : #endif
    2253           0 :     throw QDomXPathException_InternalError("the End instruction is not expected to be executed");
    2254             : }
    2255             : 
    2256             : 
    2257             : /** \brief The Call instruction.
    2258             :  *
    2259             :  * This function creates a new function_t with its PC set to the function
    2260             :  * being called as found on the stack (the last PUSH is the PC of the
    2261             :  * function being called.)
    2262             :  *
    2263             :  * The arguments are also popped from the input stack, up until the
    2264             :  * End of Argument special value is found. Then this function returns
    2265             :  * which means we now are running in this sub-function.
    2266             :  */
    2267           0 : void inst_call()
    2268             : {
    2269             : #if QDOM_XPATH_VERIFICATION
    2270             :     // verify instruction location
    2271           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_CALL)
    2272             :     {
    2273           0 :         throw QDomXPathException_InternalError("INST_CALL not at the right location in the table of instructions");
    2274             :     }
    2275             : #endif
    2276             :     // get the internal function number (FUNC_...)
    2277           0 :     variant_t function_number(pop_variant_data());
    2278           0 :     if(function_number.atomic_value_t::getType() != atomic_value_t::type_t::ATOMIC_TYPE_INTEGER)
    2279             :     {
    2280           0 :         throw QDomXPathException_InternalError("INST_CALL expects the first element on the stack to be of type INTEGER");
    2281             :     }
    2282             : 
    2283             :     // save arguments in variables named "a1", "a2", "a3"...
    2284             :     // these can be accessed with "$a1", "$a2", "$a3"...
    2285             :     // --the number of arguments is saved in $argc (argument count)--
    2286           0 :     variant_vector_t arguments;
    2287           0 :     for(int a(1);; ++a)
    2288             :     {
    2289           0 :         variant_t arg(pop_variant_data());
    2290           0 :         if(arg.atomic_value_t::getType() == atomic_value_t::type_t::ATOMIC_TYPE_END_OF_ARGUMENTS)
    2291             :         {
    2292             :             // found the end of the argument list
    2293           0 :             break;
    2294             :         }
    2295           0 :         arguments.push_back(arg);
    2296           0 :     }
    2297             : 
    2298             :     // now select the function to run
    2299           0 :     switch(static_cast<internal_func_t>(function_number.getIntegerValue()))
    2300             :     {
    2301           0 :     case internal_func_t::FUNC_AVG:
    2302           0 :         func_avg(arguments);
    2303           0 :         break;
    2304             : 
    2305           0 :     case internal_func_t::FUNC_MAX:
    2306           0 :         func_max(arguments);
    2307           0 :         break;
    2308             : 
    2309           0 :     case internal_func_t::FUNC_MIN:
    2310           0 :         func_min(arguments);
    2311           0 :         break;
    2312             : 
    2313           0 :     case internal_func_t::FUNC_SUM:
    2314           0 :         func_sum(arguments);
    2315           0 :         break;
    2316             : 
    2317           0 :     default:
    2318           0 :         throw QDomXPathException_NotImplemented(QString("function %1 is not yet implemented").arg(function_number.getIntegerValue()));
    2319             : 
    2320             :     }
    2321           0 : }
    2322             : 
    2323             : 
    2324           0 : void func_default_to_context_node(variant_vector_t& arguments)
    2325             : {
    2326           0 :     if(arguments.size() == 0)
    2327             :     {
    2328             :         // retrieve the context node if no parameters were specified
    2329           0 :         context_vector_t::reference context(f_functions.back().f_contexts.back());
    2330           0 :         if(context.f_position == -1)
    2331             :         {
    2332           0 :             throw QDomXPathException_EmptyContext("the sum() function cannot be used without a context node and no parameters");
    2333             :         }
    2334           0 :         QDomXPath::node_vector_t context_node;
    2335           0 :         context_node.push_back(context.f_nodes[context.f_position]);
    2336           0 :         variant_t value;
    2337           0 :         value.setValue(context_node);
    2338           0 :         arguments.push_back(value);
    2339             :     }
    2340           0 : }
    2341             : 
    2342           0 : void func_calculate_sum_or_average(variant_vector_t& arguments, bool sum_only)
    2343             : {
    2344           0 :     func_default_to_context_node(arguments);
    2345             :     // TODO: support sums of only decimals and singles
    2346           0 :     bool integer(true);
    2347           0 :     int64_t isum(0);
    2348           0 :     int count(0);
    2349           0 :     double dsum(0.0);
    2350           0 :     const int imax(arguments.size());
    2351           0 :     for(int i(0); i < imax; ++i)
    2352             :     {
    2353           0 :         variant_t arg(arguments[i]);
    2354           0 :         switch(arg.getType())
    2355             :         {
    2356           0 :         case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    2357           0 :             if(integer)
    2358             :             {
    2359           0 :                 isum += arg.getIntegerValue();
    2360           0 :                 dsum = static_cast<double>(isum);
    2361           0 :                 ++count;
    2362           0 :                 break;
    2363             :             }
    2364             : #if __cplusplus >= 201700
    2365             :             [[fallthrough]];
    2366             : #endif
    2367             :         //case atomic_type_t::ATOMIC_TYPE_DECIMAL:
    2368             :         case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    2369             :         case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    2370           0 :             integer = false;
    2371           0 :             dsum += arg.getDoubleValue(true);
    2372           0 :             ++count;
    2373           0 :             break;
    2374             : 
    2375           0 :         case atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET:
    2376             :             {
    2377           0 :                 integer = false;
    2378           0 :                 QDomXPath::node_vector_t node_set(arg.getNodeSetValue());
    2379           0 :                 const int jmax(node_set.size());
    2380           0 :                 for(int j(0); j < jmax; ++j)
    2381             :                 {
    2382           0 :                     QString str(variant_t::node_to_string(node_set[j]));
    2383             :                     // TODO verify that the string is a valid number
    2384             :                     // TODO if the number is decimal, avoid forcing double
    2385             :                     // (in XPath 2.0 we can use the best possible type as
    2386             :                     // defined here: http://www.w3.org/TR/xpath20/#promotion )
    2387           0 :                     dsum += atof(str.toUtf8().data());
    2388           0 :                     ++count;
    2389           0 :                 }
    2390             :             }
    2391           0 :             break;
    2392             : 
    2393           0 :         default:
    2394           0 :             throw QDomXPathException_WrongType("the sum/avg() functions cannot be used with types other than numbers and node-set");
    2395             : 
    2396             :         }
    2397             :     }
    2398             : 
    2399           0 :     variant_t return_value;
    2400           0 :     if(integer && sum_only)
    2401             :     {
    2402           0 :         return_value.atomic_value_t::setValue(isum);
    2403             :     }
    2404             :     else
    2405             :     {
    2406           0 :         if(!sum_only && count > 0)
    2407             :         {
    2408             :             // compute the average
    2409           0 :             dsum /= static_cast<double>(count);
    2410             :         }
    2411           0 :         return_value.atomic_value_t::setValue(dsum);
    2412             :     }
    2413           0 :     f_functions.back().f_stack.push_back(return_value);
    2414           0 : }
    2415             : 
    2416             : 
    2417           0 : void func_sum(variant_vector_t& arguments)
    2418             : {
    2419           0 :     func_calculate_sum_or_average(arguments, true);
    2420           0 : }
    2421             : 
    2422             : 
    2423           0 : void func_avg(variant_vector_t& arguments)
    2424             : {
    2425           0 :     func_calculate_sum_or_average(arguments, false);
    2426           0 : }
    2427             : 
    2428             : 
    2429           0 : void func_calculate_min_or_max(variant_vector_t& arguments, bool min)
    2430             : {
    2431           0 :     func_default_to_context_node(arguments);
    2432             :     // TODO: support min/max of only decimals and singles
    2433             :     // TODO: support min/max on strings (XPath 2.0 supports such + collation)
    2434           0 :     bool integer(true);
    2435           0 :     bool first(true);
    2436           0 :     int64_t iresult(0);
    2437           0 :     double dresult(0.0);
    2438           0 :     const int imax(arguments.size());
    2439           0 :     for(int i(0); i < imax; ++i)
    2440             :     {
    2441           0 :         variant_t arg(arguments[i]);
    2442           0 :         switch(arg.getType())
    2443             :         {
    2444           0 :         case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    2445           0 :             if(integer)
    2446             :             {
    2447           0 :                 int64_t v(arg.getIntegerValue());
    2448           0 :                 if(v > iresult ^ min || first)
    2449             :                 {
    2450           0 :                     iresult = v;
    2451           0 :                     first = false;
    2452             :                 }
    2453           0 :                 dresult = static_cast<double>(iresult);
    2454           0 :                 break;
    2455           0 :             }
    2456             : #if __cplusplus >= 201700
    2457             :             [[fallthrough]];
    2458             : #endif
    2459             :         //case atomic_type_t::ATOMIC_TYPE_DECIMAL:
    2460             :         case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    2461             :         case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    2462           0 :             integer = false;
    2463             :             {
    2464           0 :                 double v(arg.getDoubleValue(true));
    2465           0 :                 if(v > dresult ^ min || first)
    2466             :                 {
    2467           0 :                     dresult = v;
    2468           0 :                     first = false;
    2469           0 :                 }
    2470             :             }
    2471           0 :             break;
    2472             : 
    2473           0 :         case atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET:
    2474             :             {
    2475           0 :                 integer = false;
    2476           0 :                 QDomXPath::node_vector_t node_set(arg.getNodeSetValue());
    2477           0 :                 const int jmax(node_set.size());
    2478           0 :                 for(int j(0); j < jmax; ++j)
    2479             :                 {
    2480           0 :                     QString str(variant_t::node_to_string(node_set[j]));
    2481             :                     // TODO verify that the string is a valid number
    2482             :                     // TODO if the number is decimal, avoid forcing double
    2483             :                     // (in XPath 2.0 we can use the best possible type as
    2484             :                     // defined here: http://www.w3.org/TR/xpath20/#promotion )
    2485           0 :                     double v(atof(str.toUtf8().data()));
    2486           0 :                     if(v > dresult ^ min || first)
    2487             :                     {
    2488           0 :                         dresult = v;
    2489           0 :                         first = false;
    2490             :                     }
    2491           0 :                 }
    2492             :             }
    2493           0 :             break;
    2494             : 
    2495           0 :         default:
    2496           0 :             throw QDomXPathException_WrongType("the min/max() functions cannot be used with types other than numbers and node-set");
    2497             : 
    2498             :         }
    2499             :     }
    2500             : 
    2501           0 :     variant_t return_value;
    2502           0 :     if(integer)
    2503             :     {
    2504           0 :         return_value.atomic_value_t::setValue(iresult);
    2505             :     }
    2506             :     else
    2507             :     {
    2508           0 :         return_value.atomic_value_t::setValue(dresult);
    2509             :     }
    2510           0 :     f_functions.back().f_stack.push_back(return_value);
    2511           0 : }
    2512             : 
    2513             : 
    2514           0 : void func_max(variant_vector_t& arguments)
    2515             : {
    2516           0 :     func_calculate_min_or_max(arguments, false);
    2517           0 : }
    2518             : 
    2519             : 
    2520           0 : void func_min(variant_vector_t& arguments)
    2521             : {
    2522           0 :     func_calculate_min_or_max(arguments, true);
    2523           0 : }
    2524             : 
    2525             : 
    2526             : /** \brief Return from a function.
    2527             :  *
    2528             :  * This instruction allows the instruction stream to return to the caller.
    2529             :  *
    2530             :  * The last variant that got pushed on the stack is returned to the caller.
    2531             :  */
    2532           0 : void inst_return()
    2533             : {
    2534             : #if QDOM_XPATH_VERIFICATION
    2535             :     // verify instruction location
    2536           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_RETURN)
    2537             :     {
    2538           0 :         throw QDomXPathException_InternalError("INST_RETURN not at the right location in the table of instructions");
    2539             :     }
    2540           0 :     if(f_functions.size() <= 1)
    2541             :     {
    2542           0 :         throw QDomXPathException_InternalError("INST_RETURN cannot be called with an empty stack of functions");
    2543             :     }
    2544             : #endif
    2545             :     // copy the return value from the function stack
    2546             :     // to the caller's stack
    2547           0 :     variant_t return_value(pop_variant_data());
    2548             : 
    2549             :     // now return to the old function
    2550           0 :     f_functions.pop_back();
    2551             : 
    2552           0 :     f_functions.back().f_stack.push_back(return_value);
    2553           0 : }
    2554             : 
    2555             : 
    2556             : /** \brief Get the contents of a variable.
    2557             :  *
    2558             :  * This instruction retrieves the contents of a variable. First the function
    2559             :  * checks the current function. If the current function does not define such
    2560             :  * a variable, then the user bound variables are checked.
    2561             :  *
    2562             :  * If no variable with that name is defined, then an error is raised.
    2563             :  */
    2564           0 : void inst_get_variable()
    2565             : {
    2566             : #if QDOM_XPATH_VERIFICATION
    2567             :     // verify instruction location
    2568           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GET_VARIABLE)
    2569             :     {
    2570           0 :         throw QDomXPathException_InternalError("INST_GET_VARIABLE not at the right location in the table of instructions");
    2571             :     }
    2572             : #endif
    2573             :     // retrieve variable name
    2574           0 :     variant_t variable(pop_variant_data());
    2575           0 :     QString variable_name(variable.getStringValue());
    2576             : 
    2577           0 :     if(f_functions.back().f_variables.contains(variable_name))
    2578             :     {
    2579           0 :         f_functions.back().f_stack.push_back(f_functions.back().f_variables[variable_name]);
    2580             :     }
    2581             :     else
    2582             :     {
    2583           0 :         variant_t value;
    2584           0 :         value.atomic_value_t::setValue(f_owner->getVariable(variable_name));
    2585           0 :         f_functions.back().f_stack.push_back(value);
    2586             :     }
    2587           0 : }
    2588             : 
    2589             : 
    2590             : 
    2591             : /** \brief Set the contents of a variable.
    2592             :  *
    2593             :  * This instruction sets the contents of a variable. The variable is set in
    2594             :  * the current function only. There is currently no function to change a
    2595             :  * global variable.
    2596             :  */
    2597           0 : void inst_set_variable()
    2598             : {
    2599             : #if QDOM_XPATH_VERIFICATION
    2600             :     // verify instruction location
    2601           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SET_VARIABLE)
    2602             :     {
    2603           0 :         throw QDomXPathException_InternalError("INST_SET_VARIABLE not at the right location in the table of instructions");
    2604             :     }
    2605             : #endif
    2606             :     // retrieve variable name
    2607           0 :     variant_t variable(pop_variant_data());
    2608           0 :     QString variable_name(variable.getStringValue());
    2609             : 
    2610             :     // retrieve the value for the variable
    2611           0 :     variant_t value(pop_variant_data());
    2612             : 
    2613           0 :     f_functions.back().f_variables[variable_name] = value;
    2614           0 : }
    2615             : 
    2616             : 
    2617             : /** \brief Found a function.
    2618             :  *
    2619             :  * Functions are just inline code that gets skipped when bumped into.
    2620             :  * Functions are not named, they just have an offset so we do not need
    2621             :  * to do anything special about them. At a later time, we may have to
    2622             :  * handle user functions, but I have the impression that those would
    2623             :  * be quite different that this.
    2624             :  *
    2625             :  * The size of the small function is 16 bits.
    2626             :  */
    2627           0 : void inst_small_function()
    2628             : {
    2629             : #if QDOM_XPATH_VERIFICATION
    2630             :     // verify instruction location
    2631           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SMALL_FUNCTION)
    2632             :     {
    2633           0 :         throw QDomXPathException_InternalError("INST_PUSH_END_OF_ARGUMENTS not at the right location in the table of instructions");
    2634             :     }
    2635             : #endif
    2636           0 :     int size((get_next_program_byte() << 8) | get_next_program_byte());
    2637           0 :     f_functions.back().f_pc += size;
    2638           0 : }
    2639             : 
    2640             : 
    2641             : /** \brief Found a function.
    2642             :  *
    2643             :  * Functions are just inline code that gets skipped when bumped into.
    2644             :  * Functions are not named, they just have an offset so we do not need
    2645             :  * to do anything special about them. At a later time, we may have to
    2646             :  * handle user functions, but I have the impression that those would
    2647             :  * be quite different that this.
    2648             :  *
    2649             :  * The size of the large function is 32 bits.
    2650             :  */
    2651           0 : void inst_large_function()
    2652             : {
    2653             : #if QDOM_XPATH_VERIFICATION
    2654             :     // verify instruction location
    2655           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_LARGE_FUNCTION)
    2656             :     {
    2657           0 :         throw QDomXPathException_InternalError("INST_LARGE_FUNCTION not at the right location in the table of instructions");
    2658             :     }
    2659             : #endif
    2660           0 :     int size((get_next_program_byte() << 24)
    2661           0 :            | (get_next_program_byte() << 16)
    2662           0 :            | (get_next_program_byte() << 8)
    2663           0 :            | get_next_program_byte());
    2664           0 :     f_functions.back().f_pc += size;
    2665           0 : }
    2666             : 
    2667             : 
    2668             : /** \brief Jump to a new location.
    2669             :  *
    2670             :  * Jump to a new location as found on the stack.
    2671             :  */
    2672           0 : void inst_jump()
    2673             : {
    2674             : #if QDOM_XPATH_VERIFICATION
    2675             :     // verify instruction location
    2676           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_JUMP)
    2677             :     {
    2678           0 :         throw QDomXPathException_InternalError("INST_JUMP not at the right location in the table of instructions");
    2679             :     }
    2680             : #endif
    2681           0 :     variant_t pc(pop_variant_data());
    2682           0 :     f_functions.back().f_pc = static_cast<uint32_t>(pc.getIntegerValue());
    2683           0 : }
    2684             : 
    2685             : 
    2686             : /** \brief Jump to a new location if true.
    2687             :  *
    2688             :  * This function pops a new location and then a Boolean value. If the
    2689             :  * Boolean value is false, the new location is ignored. If the Boolean
    2690             :  * value is true, then PC becomes that new location.
    2691             :  */
    2692           0 : void inst_jump_if_true()
    2693             : {
    2694             : #if QDOM_XPATH_VERIFICATION
    2695             :     // verify instruction location
    2696           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_JUMP_IF_TRUE)
    2697             :     {
    2698           0 :         throw QDomXPathException_InternalError("INST_JUMP_IF_TRUE not at the right location in the table of instructions");
    2699             :     }
    2700             : #endif
    2701           0 :     variant_t pc(pop_variant_data());
    2702           0 :     variant_t boolean(pop_variant_data());
    2703           0 :     if(boolean.getBooleanValue())
    2704             :     {
    2705           0 :         f_functions.back().f_pc = static_cast<uint32_t>(pc.getIntegerValue());
    2706             :     }
    2707           0 : }
    2708             : 
    2709             : 
    2710             : /** \brief Jump to a new location if false.
    2711             :  *
    2712             :  * This function pops a new location and then a Boolean value. If the
    2713             :  * Boolean value is true, the new location is ignored. If the Boolean
    2714             :  * value is false, then PC becomes that new location.
    2715             :  */
    2716           0 : void inst_jump_if_false()
    2717             : {
    2718             : #if QDOM_XPATH_VERIFICATION
    2719             :     // verify instruction location
    2720           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_JUMP_IF_FALSE)
    2721             :     {
    2722           0 :         throw QDomXPathException_InternalError("INST_JUMP_IF_FALSE not at the right location in the table of instructions");
    2723             :     }
    2724             : #endif
    2725           0 :     variant_t pc(pop_variant_data());
    2726           0 :     variant_t boolean(pop_variant_data());
    2727           0 :     if(!boolean.getBooleanValue())
    2728             :     {
    2729           0 :         f_functions.back().f_pc = static_cast<uint32_t>(pc.getIntegerValue());
    2730             :     }
    2731           0 : }
    2732             : 
    2733             : 
    2734             : /** \brief Jump to a new location if zero.
    2735             :  *
    2736             :  * This function pops a new location and then a value. If the
    2737             :  * value is not zero, the new location is ignored. If the
    2738             :  * value is zero, then PC becomes that new location.
    2739             :  */
    2740           0 : void inst_jump_if_zero()
    2741             : {
    2742             : #if QDOM_XPATH_VERIFICATION
    2743             :     // verify instruction location
    2744           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_JUMP_IF_ZERO)
    2745             :     {
    2746           0 :         throw QDomXPathException_InternalError("INST_JUMP_IF_ZERO not at the right location in the table of instructions");
    2747             :     }
    2748             : #endif
    2749           0 :     variant_t pc(pop_variant_data());
    2750           0 :     variant_t object(pop_variant_data());
    2751           0 :     if(object.getIntegerValue(true) == 0)
    2752             :     {
    2753           0 :         f_functions.back().f_pc = static_cast<uint32_t>(pc.getIntegerValue());
    2754             :     }
    2755           0 : }
    2756             : 
    2757             : 
    2758             : /** \brief Pop one object from the stack.
    2759             :  *
    2760             :  * This instruction pops one object from the top of the stack.
    2761             :  *
    2762             :  * \code
    2763             :  * before   after
    2764             :  * o1       o2
    2765             :  * o2       o3
    2766             :  * o3       ...
    2767             :  * ...
    2768             :  * \endcode
    2769             :  */
    2770           0 : void inst_pop1()
    2771             : {
    2772             : #if QDOM_XPATH_VERIFICATION
    2773             :     // verify instruction location
    2774           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_POP1)
    2775             :     {
    2776           0 :         throw QDomXPathException_InternalError("INST_POP1 not at the right location in the table of instructions");
    2777             :     }
    2778             : #endif
    2779           0 :     if(f_functions.back().f_stack.size() < 1)
    2780             :     {
    2781           0 :         throw QDomXPathException_EmptyStack("cannot pop anything from an empty stack");
    2782             :     }
    2783           0 :     f_functions.back().f_stack.pop_back();
    2784           0 : }
    2785             : 
    2786             : 
    2787             : /** \brief Pop two objects from the stack.
    2788             :  *
    2789             :  * This instruction pops the second object counting from the top stack of
    2790             :  * the stack.
    2791             :  *
    2792             :  * \code
    2793             :  * before   after
    2794             :  * o1       o1
    2795             :  * o2       o3
    2796             :  * o3       ...
    2797             :  * ...
    2798             :  * \endcode
    2799             :  */
    2800           0 : void inst_pop2()
    2801             : {
    2802             : #if QDOM_XPATH_VERIFICATION
    2803             :     // verify instruction location
    2804           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_POP2)
    2805             :     {
    2806           0 :         throw QDomXPathException_InternalError("INST_POP2 not at the right location in the table of instructions");
    2807             :     }
    2808             : #endif
    2809           0 :     if(f_functions.back().f_stack.size() < 2)
    2810             :     {
    2811           0 :         throw QDomXPathException_EmptyStack("cannot pop the second object from the stack if the stack is not at least two objects");
    2812             :     }
    2813           0 :     f_functions.back().f_stack.remove(f_functions.back().f_stack.size() - 2);
    2814           0 : }
    2815             : 
    2816             : 
    2817             : /** \brief Pop three objects from the stack.
    2818             :  *
    2819             :  * This instruction pops the thrid object counting from the top stack of
    2820             :  * the stack.
    2821             :  *
    2822             :  * \code
    2823             :  * before   after
    2824             :  * o1       o1
    2825             :  * o2       o2
    2826             :  * o3       o4
    2827             :  * o4       ...
    2828             :  * ...
    2829             :  * \endcode
    2830             :  */
    2831           0 : void inst_pop3()
    2832             : {
    2833             : #if QDOM_XPATH_VERIFICATION
    2834             :     // verify instruction location
    2835           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_POP3)
    2836             :     {
    2837           0 :         throw QDomXPathException_InternalError("INST_POP3 not at the right location in the table of instructions");
    2838             :     }
    2839             : #endif
    2840           0 :     if(f_functions.back().f_stack.size() < 3)
    2841             :     {
    2842           0 :         throw QDomXPathException_EmptyStack("cannot pop the third object from the stack if the stack is not at least three objects");
    2843             :     }
    2844           0 :     f_functions.back().f_stack.remove(f_functions.back().f_stack.size() - 3);
    2845           0 : }
    2846             : 
    2847             : 
    2848             : /** \brief Pop four objects from the stack.
    2849             :  *
    2850             :  * This instruction pops the fourth object counting from the top stack of
    2851             :  * the stack.
    2852             :  *
    2853             :  * \code
    2854             :  * before   after
    2855             :  * o1       o1
    2856             :  * o2       o2
    2857             :  * o3       o3
    2858             :  * o4       o5
    2859             :  * o5       ...
    2860             :  * ...
    2861             :  * \endcode
    2862             :  */
    2863           0 : void inst_pop4()
    2864             : {
    2865             : #if QDOM_XPATH_VERIFICATION
    2866             :     // verify instruction location
    2867           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_POP4)
    2868             :     {
    2869           0 :         throw QDomXPathException_InternalError("INST_POP4 not at the right location in the table of instructions");
    2870             :     }
    2871             : #endif
    2872           0 :     if(f_functions.back().f_stack.size() < 4)
    2873             :     {
    2874           0 :         throw QDomXPathException_EmptyStack("cannot pop the forth object from the stack if the stack is not at least four objects");
    2875             :     }
    2876           0 :     f_functions.back().f_stack.remove(f_functions.back().f_stack.size() - 4);
    2877           0 : }
    2878             : 
    2879             : 
    2880             : /** \brief Pop five objects from the stack.
    2881             :  *
    2882             :  * This instruction pops the fifth object counting from the top stack of
    2883             :  * the stack.
    2884             :  *
    2885             :  * \code
    2886             :  * before   after
    2887             :  * o1       o1
    2888             :  * o2       o2
    2889             :  * o3       o3
    2890             :  * o4       o4
    2891             :  * o5       o6
    2892             :  * o6       ...
    2893             :  * ...
    2894             :  * \endcode
    2895             :  */
    2896           0 : void inst_pop5()
    2897             : {
    2898             : #if QDOM_XPATH_VERIFICATION
    2899             :     // verify instruction location
    2900           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_POP5)
    2901             :     {
    2902           0 :         throw QDomXPathException_InternalError("INST_POP5 not at the right location in the table of instructions");
    2903             :     }
    2904             : #endif
    2905           0 :     if(f_functions.back().f_stack.size() < 5)
    2906             :     {
    2907           0 :         throw QDomXPathException_EmptyStack("cannot pop the fifth object from the stack if the stack is not at least five objects");
    2908             :     }
    2909           0 :     f_functions.back().f_stack.remove(f_functions.back().f_stack.size() - 5);
    2910           0 : }
    2911             : 
    2912             : 
    2913             : /** \brief Duplicate the last object on the stack.
    2914             :  *
    2915             :  * This instruction pops the last object on the stack and then push
    2916             :  * it back twice on the stack.
    2917             :  */
    2918           0 : void inst_duplicate1()
    2919             : {
    2920             : #if QDOM_XPATH_VERIFICATION
    2921             :     // verify instruction location
    2922           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DUPLICATE1)
    2923             :     {
    2924           0 :         throw QDomXPathException_InternalError("INST_DUPLICATE1 not at the right location in the table of instructions");
    2925             :     }
    2926             : #endif
    2927           0 :     if(f_functions.back().f_stack.size() == 0)
    2928             :     {
    2929           0 :         throw QDomXPathException_EmptyStack("duplicate cannot be used with an empty stack");
    2930             :     }
    2931           0 :     variant_t value(f_functions.back().f_stack.back());
    2932           0 :     f_functions.back().f_stack.push_back(value);
    2933           0 : }
    2934             : 
    2935             : 
    2936             : /** \brief Duplicate the second to last object on the stack.
    2937             :  *
    2938             :  * This instruction gets a copy of the second to last object on the stack
    2939             :  * and push a copy on the stack.
    2940             :  */
    2941           0 : void inst_duplicate2()
    2942             : {
    2943             : #if QDOM_XPATH_VERIFICATION
    2944             :     // verify instruction location
    2945           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DUPLICATE2)
    2946             :     {
    2947           0 :         throw QDomXPathException_InternalError("INST_DUPLICATE2 not at the right location in the table of instructions");
    2948             :     }
    2949             : #endif
    2950           0 :     int size(f_functions.back().f_stack.size());
    2951           0 :     if(size <= 1)
    2952             :     {
    2953           0 :         throw QDomXPathException_EmptyStack("duplicate(2) cannot be used with a stack of less than 2 items");
    2954             :     }
    2955           0 :     variant_t value(f_functions.back().f_stack[size - 2]);
    2956           0 :     f_functions.back().f_stack.push_back(value);
    2957           0 : }
    2958             : 
    2959             : 
    2960             : /** \brief Duplicate the third to last object on the stack.
    2961             :  *
    2962             :  * This instruction gets a copy of the third to last object on the stack
    2963             :  * and push a copy on the stack.
    2964             :  */
    2965           0 : void inst_duplicate3()
    2966             : {
    2967             : #if QDOM_XPATH_VERIFICATION
    2968             :     // verify instruction location
    2969           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DUPLICATE3)
    2970             :     {
    2971           0 :         throw QDomXPathException_InternalError("INST_DUPLICATE3 not at the right location in the table of instructions");
    2972             :     }
    2973             : #endif
    2974           0 :     int size(f_functions.back().f_stack.size());
    2975           0 :     if(size <= 2)
    2976             :     {
    2977           0 :         throw QDomXPathException_EmptyStack("duplicate(3) cannot be used with a stack of less than 3 items");
    2978             :     }
    2979           0 :     variant_t value(f_functions.back().f_stack[size - 3]);
    2980           0 :     f_functions.back().f_stack.push_back(value);
    2981           0 : }
    2982             : 
    2983             : 
    2984             : /** \brief Duplicate the forth to last object on the stack.
    2985             :  *
    2986             :  * This instruction gets a copy of the forth to last object on the stack
    2987             :  * and push a copy on the stack.
    2988             :  */
    2989           0 : void inst_duplicate4()
    2990             : {
    2991             : #if QDOM_XPATH_VERIFICATION
    2992             :     // verify instruction location
    2993           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DUPLICATE4)
    2994             :     {
    2995           0 :         throw QDomXPathException_InternalError("INST_DUPLICATE4 not at the right location in the table of instructions");
    2996             :     }
    2997             : #endif
    2998           0 :     int size(f_functions.back().f_stack.size());
    2999           0 :     if(size <= 3)
    3000             :     {
    3001           0 :         throw QDomXPathException_EmptyStack("duplicate(4) cannot be used with a stack of less than 4 items");
    3002             :     }
    3003           0 :     variant_t value(f_functions.back().f_stack[size - 4]);
    3004           0 :     f_functions.back().f_stack.push_back(value);
    3005           0 : }
    3006             : 
    3007             : 
    3008             : /** \brief Duplicate the fifth to last object on the stack.
    3009             :  *
    3010             :  * This instruction gets a copy of the fifth to last object on the stack
    3011             :  * and push a copy on the stack.
    3012             :  */
    3013           0 : void inst_duplicate5()
    3014             : {
    3015             : #if QDOM_XPATH_VERIFICATION
    3016             :     // verify instruction location
    3017           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DUPLICATE5)
    3018             :     {
    3019           0 :         throw QDomXPathException_InternalError("INST_DUPLICATE5 not at the right location in the table of instructions");
    3020             :     }
    3021             : #endif
    3022           0 :     int size(f_functions.back().f_stack.size());
    3023           0 :     if(size <= 4)
    3024             :     {
    3025           0 :         throw QDomXPathException_EmptyStack("duplicate(5) cannot be used with a stack of less than 5 items");
    3026             :     }
    3027           0 :     variant_t value(f_functions.back().f_stack[size - 5]);
    3028           0 :     f_functions.back().f_stack.push_back(value);
    3029           0 : }
    3030             : 
    3031             : 
    3032             : /** \brief Swap the last two objects on the stack.
    3033             :  *
    3034             :  * This instruction pops the last two objects and push them back in the other
    3035             :  * order so the last value on the stack is the one before last and vice versa.
    3036             :  *
    3037             :  * \code
    3038             :  * Source        Destination
    3039             :  * stack a       stack b
    3040             :  * stack b       stack a
    3041             :  * stack c       stack c
    3042             :  * stack d       stack d
    3043             :  * ...           ...
    3044             :  * \endcode
    3045             :  */
    3046           0 : void inst_swap1()
    3047             : {
    3048             : #if QDOM_XPATH_VERIFICATION
    3049             :     // verify instruction location
    3050           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SWAP1)
    3051             :     {
    3052           0 :         throw QDomXPathException_InternalError("INST_SWAP1 not at the right location in the table of instructions");
    3053             :     }
    3054             : #endif
    3055           0 :     int size(f_functions.back().f_stack.size());
    3056           0 :     if(size < 2)
    3057             :     {
    3058           0 :         throw QDomXPathException_EmptyStack("swap(1) cannot be used with a stack of less than 2 items");
    3059             :     }
    3060           0 :     std::swap(f_functions.back().f_stack[size - 2], f_functions.back().f_stack[size - 1]);
    3061             :     //variant_t a(f_functions.back().f_stack[size - 2]);
    3062             :     //variant_t b(f_functions.back().f_stack[size - 1]);
    3063             :     //f_functions.back().f_stack[size - 2] = b;
    3064             :     //f_functions.back().f_stack[size - 1] = a;
    3065           0 : }
    3066             : 
    3067             : 
    3068             : /** \brief Swap the third to last object with the last object on the stack.
    3069             :  *
    3070             :  * This instruction swaps the third to last object with the last object on
    3071             :  * the stack.
    3072             :  *
    3073             :  * \code
    3074             :  * Source        Destination
    3075             :  * stack a       stack c
    3076             :  * stack b       stack b
    3077             :  * stack c       stack a
    3078             :  * stack d       stack d
    3079             :  * ...           ...
    3080             :  * \endcode
    3081             :  */
    3082           0 : void inst_swap2()
    3083             : {
    3084             : #if QDOM_XPATH_VERIFICATION
    3085             :     // verify instruction location
    3086           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SWAP2)
    3087             :     {
    3088           0 :         throw QDomXPathException_InternalError("INST_SWAP2 not at the right location in the table of instructions");
    3089             :     }
    3090             : #endif
    3091           0 :     int size(f_functions.back().f_stack.size());
    3092           0 :     if(size < 3)
    3093             :     {
    3094           0 :         throw QDomXPathException_EmptyStack("swap(3) cannot be used with a stack of less than 3 items");
    3095             :     }
    3096           0 :     std::swap(f_functions.back().f_stack[size - 3], f_functions.back().f_stack[size - 1]);
    3097           0 : }
    3098             : 
    3099             : 
    3100             : /** \brief Swap the forth to last object with the last object on the stack.
    3101             :  *
    3102             :  * This instruction swaps the forth to last object with the last object on
    3103             :  * the stack.
    3104             :  *
    3105             :  * \code
    3106             :  * Source        Destination
    3107             :  * stack a       stack d
    3108             :  * stack b       stack b
    3109             :  * stack c       stack c
    3110             :  * stack d       stack a
    3111             :  * stack e       stack e
    3112             :  * ...           ...
    3113             :  * \endcode
    3114             :  */
    3115           0 : void inst_swap3()
    3116             : {
    3117             : #if QDOM_XPATH_VERIFICATION
    3118             :     // verify instruction location
    3119           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SWAP3)
    3120             :     {
    3121           0 :         throw QDomXPathException_InternalError("INST_SWAP3 not at the right location in the table of instructions");
    3122             :     }
    3123             : #endif
    3124           0 :     int size(f_functions.back().f_stack.size());
    3125           0 :     if(size < 4)
    3126             :     {
    3127           0 :         throw QDomXPathException_EmptyStack("swap(4) cannot be used with a stack of less than 4 items");
    3128             :     }
    3129           0 :     std::swap(f_functions.back().f_stack[size - 4], f_functions.back().f_stack[size - 1]);
    3130           0 : }
    3131             : 
    3132             : 
    3133             : /** \brief Swap the fifth to last object with the last object on the stack.
    3134             :  *
    3135             :  * This instruction swaps the fifth to last object with the last object on
    3136             :  * the stack.
    3137             :  *
    3138             :  * \code
    3139             :  * Source        Destination
    3140             :  * stack a       stack e
    3141             :  * stack b       stack b
    3142             :  * stack c       stack c
    3143             :  * stack d       stack d
    3144             :  * stack e       stack a
    3145             :  * stack f       stack e
    3146             :  * ...           ...
    3147             :  * \endcode
    3148             :  */
    3149           0 : void inst_swap4()
    3150             : {
    3151             : #if QDOM_XPATH_VERIFICATION
    3152             :     // verify instruction location
    3153           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SWAP4)
    3154             :     {
    3155           0 :         throw QDomXPathException_InternalError("INST_SWAP4 not at the right location in the table of instructions");
    3156             :     }
    3157             : #endif
    3158           0 :     int size(f_functions.back().f_stack.size());
    3159           0 :     if(size < 5)
    3160             :     {
    3161           0 :         throw QDomXPathException_EmptyStack("swap(5) cannot be used with a stack of less than 5 items");
    3162             :     }
    3163           0 :     std::swap(f_functions.back().f_stack[size - 5], f_functions.back().f_stack[size - 1]);
    3164           0 : }
    3165             : 
    3166             : 
    3167             : /** \brief Swap the sixth to last object with the last object on the stack.
    3168             :  *
    3169             :  * This instruction swaps the sixth to last object with the last object on
    3170             :  * the stack.
    3171             :  *
    3172             :  * \code
    3173             :  * Source        Destination
    3174             :  * stack a       stack f
    3175             :  * stack b       stack b
    3176             :  * stack c       stack c
    3177             :  * stack d       stack d
    3178             :  * stack e       stack e
    3179             :  * stack f       stack a
    3180             :  * stack g       stack g
    3181             :  * ...           ...
    3182             :  * \endcode
    3183             :  */
    3184           0 : void inst_swap5()
    3185             : {
    3186             : #if QDOM_XPATH_VERIFICATION
    3187             :     // verify instruction location
    3188           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SWAP5)
    3189             :     {
    3190           0 :         throw QDomXPathException_InternalError("INST_SWAP5 not at the right location in the table of instructions");
    3191             :     }
    3192             : #endif
    3193           0 :     int size(f_functions.back().f_stack.size());
    3194           0 :     if(size < 6)
    3195             :     {
    3196           0 :         throw QDomXPathException_EmptyStack("swap(6) cannot be used with a stack of less than 6 items");
    3197             :     }
    3198           0 :     std::swap(f_functions.back().f_stack[size - 6], f_functions.back().f_stack[size - 1]);
    3199           0 : }
    3200             : 
    3201             : 
    3202             : /** \brief Swap the second object with the thrid object.
    3203             :  *
    3204             :  * This instruction swaps the second and third objects.
    3205             :  *
    3206             :  * \code
    3207             :  * Source        Destination
    3208             :  * stack a       stack a
    3209             :  * stack b       stack c
    3210             :  * stack c       stack b
    3211             :  * stack d       stack d
    3212             :  * ...           ...
    3213             :  * \endcode
    3214             :  */
    3215           0 : void inst_swap2_3()
    3216             : {
    3217             : #if QDOM_XPATH_VERIFICATION
    3218             :     // verify instruction location
    3219           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SWAP2_3)
    3220             :     {
    3221           0 :         throw QDomXPathException_InternalError("INST_SWAP2_3 not at the right location in the table of instructions");
    3222             :     }
    3223             : #endif
    3224           0 :     const int size(f_functions.back().f_stack.size());
    3225           0 :     if(size < 3)
    3226             :     {
    3227           0 :         throw QDomXPathException_EmptyStack("swap(2, 3) cannot be used with a stack of less than 3 items");
    3228             :     }
    3229           0 :     std::swap(f_functions.back().f_stack[size - 3], f_functions.back().f_stack[size - 2]);
    3230           0 : }
    3231             : 
    3232             : 
    3233             : /** \brief Push the special value: End of Arguments.
    3234             :  *
    3235             :  * This function pushes the End of Arguments special mark on the stack.
    3236             :  * This special value is used to end the list of arguments. It is as fast
    3237             :  * as having a counter and know how many arguments are defined to call
    3238             :  * a function.
    3239             :  */
    3240           0 : void inst_push_end_of_arguments()
    3241             : {
    3242             : #if QDOM_XPATH_VERIFICATION
    3243             :     // verify instruction location
    3244           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_END_OF_ARGUMENTS)
    3245             :     {
    3246           0 :         throw QDomXPathException_InternalError("INST_PUSH_END_OF_ARGUMENTS not at the right location in the table of instructions");
    3247             :     }
    3248             : #endif
    3249           0 :     variant_t value;
    3250           0 :     value.atomic_value_t::setEndOfArguments();
    3251           0 :     f_functions.back().f_stack.push_back(value);
    3252           0 : }
    3253             : 
    3254             : /** \brief Push the empty node set.
    3255             :  *
    3256             :  * This function pushes an empty set of nodes on the stack.
    3257             :  */
    3258           0 : void inst_push_empty_node_set()
    3259             : {
    3260             : #if QDOM_XPATH_VERIFICATION
    3261             :     // verify instruction location
    3262           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_EMPTY_NODE_SET)
    3263             :     {
    3264           0 :         throw QDomXPathException_InternalError("INST_PUSH_EMPTY_NODE_SET not at the right location in the table of instructions");
    3265             :     }
    3266             : #endif
    3267           0 :     variant_t value;
    3268           0 :     QDomXPath::node_vector_t empty;
    3269           0 :     value.setValue(empty);
    3270           0 :     f_functions.back().f_stack.push_back(value);
    3271           0 : }
    3272             : 
    3273             : /** \brief Push the empty atomic set.
    3274             :  *
    3275             :  * This function pushes an empty set of atomic values on the stack.
    3276             :  */
    3277           0 : void inst_push_empty_set()
    3278             : {
    3279             : #if QDOM_XPATH_VERIFICATION
    3280             :     // verify instruction location
    3281           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_EMPTY_SET)
    3282             :     {
    3283           0 :         throw QDomXPathException_InternalError("INST_PUSH_EMPTY_SET not at the right location in the table of instructions");
    3284             :     }
    3285             : #endif
    3286           0 :     variant_t value;
    3287           0 :     atomic_vector_t empty;
    3288           0 :     value.setValue(empty);
    3289           0 :     f_functions.back().f_stack.push_back(value);
    3290           0 : }
    3291             : 
    3292             : /** \brief Push the "" string.
    3293             :  *
    3294             :  * This function pushes the "*" string on the stack.
    3295             :  */
    3296           0 : void inst_push_empty_string()
    3297             : {
    3298             : #if QDOM_XPATH_VERIFICATION
    3299             :     // verify instruction location
    3300           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_EMPTY_STRING)
    3301             :     {
    3302           0 :         throw QDomXPathException_InternalError("INST_PUSH_EMPTY_STRING not at the right location in the table of instructions");
    3303             :     }
    3304             : #endif
    3305           0 :     variant_t value;
    3306           0 :     value.atomic_value_t::setValue("");
    3307           0 :     f_functions.back().f_stack.push_back(value);
    3308           0 : }
    3309             : 
    3310             : /** \brief Push the "*" string.
    3311             :  *
    3312             :  * This function pushes the "*" string on the stack.
    3313             :  */
    3314           0 : void inst_push_any_string()
    3315             : {
    3316             : #if QDOM_XPATH_VERIFICATION
    3317             :     // verify instruction location
    3318           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_ANY_STRING)
    3319             :     {
    3320           0 :         throw QDomXPathException_InternalError("INST_PUSH_ANY_STRING not at the right location in the table of instructions");
    3321             :     }
    3322             : #endif
    3323           0 :     variant_t value;
    3324           0 :     value.atomic_value_t::setValue("*");
    3325           0 :     f_functions.back().f_stack.push_back(value);
    3326           0 : }
    3327             : 
    3328             : /** \brief Push a small string.
    3329             :  *
    3330             :  * This function pushes the string as defined by the push instruction.
    3331             :  * This string is limited to 0 to 255 characters.
    3332             :  */
    3333           0 : void inst_push_small_string()
    3334             : {
    3335             : #if QDOM_XPATH_VERIFICATION
    3336             :     // verify instruction location
    3337           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_SMALL_STRING)
    3338             :     {
    3339           0 :         throw QDomXPathException_InternalError("INST_PUSH_SMALL_STRING not at the right location in the table of instructions");
    3340             :     }
    3341             : #endif
    3342           0 :     int length(static_cast<int>(get_next_program_byte()));
    3343           0 :     variant_t value;
    3344           0 :     value.atomic_value_t::setValue(QString::fromUtf8(reinterpret_cast<char *>(f_program.data() + f_functions.back().f_pc), length));
    3345           0 :     f_functions.back().f_pc += length;
    3346           0 :     f_functions.back().f_stack.push_back(value);
    3347           0 : }
    3348             : 
    3349             : /** \brief Push a medium string.
    3350             :  *
    3351             :  * This function pushes the string as defined by the push instruction.
    3352             :  * This string is limited to 1 to 65535 characters (although strings
    3353             :  * of 1 to 255 characters are considered Small Strings and this
    3354             :  * PUSH would not apply to them.)
    3355             :  */
    3356           0 : void inst_push_medium_string()
    3357             : {
    3358             : #if QDOM_XPATH_VERIFICATION
    3359             :     // verify instruction location
    3360           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_MEDIUM_STRING)
    3361             :     {
    3362           0 :         throw QDomXPathException_InternalError("INST_PUSH_MEDIUM_STRING not at the right location in the table of instructions");
    3363             :     }
    3364             : #endif
    3365           0 :     int64_t length((static_cast<int>(get_next_program_byte()) << 8)
    3366           0 :                   | static_cast<int>(get_next_program_byte()));
    3367           0 :     variant_t value;
    3368           0 :     value.atomic_value_t::setValue(QString::fromUtf8(reinterpret_cast<char *>(f_program.data() + f_functions.back().f_pc), static_cast<int>(length)));
    3369           0 :     f_functions.back().f_pc += static_cast<uint32_t>(length);
    3370           0 :     f_functions.back().f_stack.push_back(value);
    3371           0 : }
    3372             : 
    3373             : /** \brief Push a large string.
    3374             :  *
    3375             :  * This function pushes the string as defined by the push instruction.
    3376             :  * This string is limited to 1 to 4 billion characters (although strings
    3377             :  * of 1 to 255 characters are considered Small Strings, also strings of
    3378             :  * 256 to 65535 characters are considered Medium Strings and this
    3379             :  * PUSH would not apply to either one of those cases.)
    3380             :  *
    3381             :  * Note that if you have a string this big... You may have a problem in
    3382             :  * that XPath.
    3383             :  */
    3384           0 : void inst_push_large_string()
    3385             : {
    3386             : #if QDOM_XPATH_VERIFICATION
    3387             :     // verify instruction location
    3388           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_LARGE_STRING)
    3389             :     {
    3390           0 :         throw QDomXPathException_InternalError("INST_PUSH_LARGE_STRING not at the right location in the table of instructions");
    3391             :     }
    3392             : #endif
    3393           0 :     int64_t length((static_cast<int>(get_next_program_byte()) << 24)
    3394           0 :                  | (static_cast<int>(get_next_program_byte()) << 16)
    3395           0 :                  | (static_cast<int>(get_next_program_byte()) << 8)
    3396           0 :                  |  static_cast<int>(get_next_program_byte()));
    3397           0 :     variant_t value;
    3398           0 :     value.atomic_value_t::setValue(QString::fromUtf8(reinterpret_cast<char *>(f_program.data() + f_functions.back().f_pc), static_cast<int>(length)));
    3399           0 :     f_functions.back().f_pc += static_cast<uint32_t>(length);
    3400           0 :     f_functions.back().f_stack.push_back(value);
    3401           0 : }
    3402             : 
    3403             : /** \brief Push the zero integer on the stack.
    3404             :  *
    3405             :  * This function pushes the value zero on the stack.
    3406             :  */
    3407           0 : void inst_push_zero()
    3408             : {
    3409             : #if QDOM_XPATH_VERIFICATION
    3410             :     // verify instruction location
    3411           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_ZERO)
    3412             :     {
    3413           0 :         throw QDomXPathException_InternalError("INST_PUSH_ZERO not at the right location in the table of instructions");
    3414             :     }
    3415             : #endif
    3416           0 :     variant_t value;
    3417           0 :     int64_t zero(0);
    3418           0 :     value.atomic_value_t::setValue(zero);
    3419           0 :     f_functions.back().f_stack.push_back(value);
    3420           0 : }
    3421             : 
    3422             : /** \brief Push the Boolean true.
    3423             :  *
    3424             :  * This function pushes the Boolean true on the stack.
    3425             :  */
    3426           0 : void inst_push_true()
    3427             : {
    3428             : #if QDOM_XPATH_VERIFICATION
    3429             :     // verify instruction location
    3430           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_TRUE)
    3431             :     {
    3432           0 :         throw QDomXPathException_InternalError("INST_PUSH_TRUE not at the right location in the table of instructions");
    3433             :     }
    3434             : #endif
    3435           0 :     variant_t value;
    3436           0 :     value.atomic_value_t::setValue(true);
    3437           0 :     f_functions.back().f_stack.push_back(value);
    3438           0 : }
    3439             : 
    3440             : /** \brief Push the Boolean false.
    3441             :  *
    3442             :  * This function pushes the Boolean false on the stack.
    3443             :  */
    3444           0 : void inst_push_false()
    3445             : {
    3446             : #if QDOM_XPATH_VERIFICATION
    3447             :     // verify instruction location
    3448           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_FALSE)
    3449             :     {
    3450           0 :         throw QDomXPathException_InternalError("INST_PUSH_FALSE not at the right location in the table of instructions");
    3451             :     }
    3452             : #endif
    3453           0 :     variant_t value;
    3454           0 :     value.atomic_value_t::setValue(false);
    3455           0 :     f_functions.back().f_stack.push_back(value);
    3456           0 : }
    3457             : 
    3458             : /** \brief Push an integer on the stack from one byte.
    3459             :  *
    3460             :  * This function reads one byte from the program and pushes it on the stack.
    3461             :  * The byte is taken as an unsigned integer (0 to 255).
    3462             :  */
    3463           0 : void inst_push_byte()
    3464             : {
    3465             : #if QDOM_XPATH_VERIFICATION
    3466             :     // verify instruction location
    3467           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_BYTE)
    3468             :     {
    3469           0 :         throw QDomXPathException_InternalError("INST_PUSH_BYTE not at the right location in the table of instructions");
    3470             :     }
    3471             : #endif
    3472           0 :     variant_t value;
    3473           0 :     value.atomic_value_t::setValue(static_cast<int64_t>(get_next_program_byte()));
    3474           0 :     f_functions.back().f_stack.push_back(value);
    3475           0 : }
    3476             : 
    3477             : /** \brief Push an integer on the stack from one negative byte.
    3478             :  *
    3479             :  * This function reads one byte from the program and pushes it on the stack.
    3480             :  * The byte is taken as a negative integer (-256 to -1).
    3481             :  */
    3482           0 : void inst_push_negative_byte()
    3483             : {
    3484             : #if QDOM_XPATH_VERIFICATION
    3485             :     // verify instruction location
    3486           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_NEGATIVE_BYTE)
    3487             :     {
    3488           0 :         throw QDomXPathException_InternalError("INST_PUSH_NEGATIVE_BYTE not at the right location in the table of instructions");
    3489             :     }
    3490             : #endif
    3491           0 :     variant_t value;
    3492           0 :     value.atomic_value_t::setValue(static_cast<int64_t>(get_next_program_byte() | 0xFFFFFFFFFFFFFF00LL));
    3493           0 :     f_functions.back().f_stack.push_back(value);
    3494           0 : }
    3495             : 
    3496             : /** \brief Push an integer on the stack from two bytes.
    3497             :  *
    3498             :  * This function reads two bytes from the program and pushes them on the stack
    3499             :  * as a short.
    3500             :  *
    3501             :  * The bytes are viewed as an unsigned integer (0 to 65535).
    3502             :  */
    3503           0 : void inst_push_short()
    3504             : {
    3505             : #if QDOM_XPATH_VERIFICATION
    3506             :     // verify instruction location
    3507           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_SHORT)
    3508             :     {
    3509           0 :         throw QDomXPathException_InternalError("INST_PUSH_SHORT not at the right location in the table of instructions");
    3510             :     }
    3511             : #endif
    3512           0 :     variant_t value;
    3513           0 :     value.atomic_value_t::setValue((static_cast<int64_t>(get_next_program_byte()) << 8)
    3514           0 :                                   | static_cast<int64_t>(get_next_program_byte()));
    3515           0 :     f_functions.back().f_stack.push_back(value);
    3516           0 : }
    3517             : 
    3518             : /** \brief Push an integer on the stack from two negative bytes.
    3519             :  *
    3520             :  * This function reads two bytes from the program and pushes them on the stack
    3521             :  * after making all the other bits 1's since the bytes are taken as a
    3522             :  * negative integer (-65536 to -1).
    3523             :  */
    3524           0 : void inst_push_negative_short()
    3525             : {
    3526             : #if QDOM_XPATH_VERIFICATION
    3527             :     // verify instruction location
    3528           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_NEGATIVE_SHORT)
    3529             :     {
    3530           0 :         throw QDomXPathException_InternalError("INST_PUSH_NEGATIVE_SHORT not at the right location in the table of instructions");
    3531             :     }
    3532             : #endif
    3533           0 :     variant_t value;
    3534           0 :     value.atomic_value_t::setValue((static_cast<int64_t>(get_next_program_byte() << 8)
    3535           0 :                                   | static_cast<int64_t>(get_next_program_byte())
    3536           0 :                                   | static_cast<int64_t>(0xFFFFFFFFFFFF0000LL)));
    3537           0 :     f_functions.back().f_stack.push_back(value);
    3538           0 : }
    3539             : 
    3540             : /** \brief Push an integer on the stack from four bytes.
    3541             :  *
    3542             :  * This function reads four bytes from the program and pushes them on the stack
    3543             :  * as a long.
    3544             :  *
    3545             :  * The bytes are viewed as an unsigned integer (0 to 0xFFFFFFFF).
    3546             :  */
    3547           0 : void inst_push_long()
    3548             : {
    3549             : #if QDOM_XPATH_VERIFICATION
    3550             :     // verify instruction location
    3551           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_LONG)
    3552             :     {
    3553           0 :         throw QDomXPathException_InternalError("INST_PUSH_LONG not at the right location in the table of instructions");
    3554             :     }
    3555             : #endif
    3556           0 :     variant_t value;
    3557           0 :     value.atomic_value_t::setValue((static_cast<int64_t>(get_next_program_byte()) << 24)
    3558           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 16)
    3559           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 8)
    3560           0 :                                  |  static_cast<int64_t>(get_next_program_byte()));
    3561           0 :     f_functions.back().f_stack.push_back(value);
    3562           0 : }
    3563             : 
    3564             : /** \brief Push an integer on the stack from four negative bytes.
    3565             :  *
    3566             :  * This function reads four bytes from the program and pushes them on the stack
    3567             :  * after making all the other bits 1's since the bytes are taken as a
    3568             :  * negative integer (-0x100000000 to -1).
    3569             :  */
    3570           0 : void inst_push_negative_long()
    3571             : {
    3572             : #if QDOM_XPATH_VERIFICATION
    3573             :     // verify instruction location
    3574           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_NEGATIVE_LONG)
    3575             :     {
    3576           0 :         throw QDomXPathException_InternalError("INST_PUSH_NEGATIVE_LONG not at the right location in the table of instructions");
    3577             :     }
    3578             : #endif
    3579           0 :     variant_t value;
    3580           0 :     value.atomic_value_t::setValue((static_cast<int64_t>(get_next_program_byte()) << 24)
    3581           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 16)
    3582           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 8)
    3583           0 :                                  |  static_cast<int64_t>(get_next_program_byte())
    3584             :                                  |  static_cast<int64_t>(0xFFFFFFFF00000000LL));
    3585           0 :     f_functions.back().f_stack.push_back(value);
    3586           0 : }
    3587             : 
    3588             : /** \brief Push an integer on the stack from eight bytes.
    3589             :  *
    3590             :  * This function reads eight bytes from the program and pushes them on the
    3591             :  * stack as a long long.
    3592             :  */
    3593           0 : void inst_push_longlong()
    3594             : {
    3595             : #if QDOM_XPATH_VERIFICATION
    3596             :     // verify instruction location
    3597           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_LONGLONG)
    3598             :     {
    3599           0 :         throw QDomXPathException_InternalError("INST_PUSH_LONGLONG not at the right location in the table of instructions");
    3600             :     }
    3601             : #endif
    3602           0 :     variant_t value;
    3603           0 :     value.atomic_value_t::setValue((static_cast<int64_t>(get_next_program_byte()) << 56)
    3604           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 48)
    3605           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 40)
    3606           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 32)
    3607           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 24)
    3608           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 16)
    3609           0 :                                  | (static_cast<int64_t>(get_next_program_byte()) << 8)
    3610           0 :                                  |  static_cast<int64_t>(get_next_program_byte()));
    3611           0 :     f_functions.back().f_stack.push_back(value);
    3612           0 : }
    3613             : 
    3614             : /** \brief Push a Double on the stack from eight bytes.
    3615             :  *
    3616             :  * This function reads eight bytes from the program and pushes them on the
    3617             :  * stack as a double.
    3618             :  */
    3619           0 : void inst_push_double()
    3620             : {
    3621             : #if QDOM_XPATH_VERIFICATION
    3622             :     // verify instruction location
    3623           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_DOUBLE)
    3624             :     {
    3625           0 :         throw QDomXPathException_InternalError("INST_PUSH_DOUBLE not at the right location in the table of instructions");
    3626             :     }
    3627             : #endif
    3628             :     union
    3629             :     {
    3630             :         uint64_t    f_int;
    3631             :         double      f_dbl;
    3632             :     } convert;
    3633           0 :     convert.f_int = (static_cast<int64_t>(get_next_program_byte()) << 56)
    3634           0 :                   | (static_cast<int64_t>(get_next_program_byte()) << 48)
    3635           0 :                   | (static_cast<int64_t>(get_next_program_byte()) << 40)
    3636           0 :                   | (static_cast<int64_t>(get_next_program_byte()) << 32)
    3637           0 :                   | (static_cast<int64_t>(get_next_program_byte()) << 24)
    3638           0 :                   | (static_cast<int64_t>(get_next_program_byte()) << 16)
    3639           0 :                   | (static_cast<int64_t>(get_next_program_byte()) << 8)
    3640           0 :                   |  static_cast<int64_t>(get_next_program_byte());
    3641           0 :     variant_t value;
    3642           0 :     value.atomic_value_t::setValue(convert.f_dbl);
    3643           0 :     f_functions.back().f_stack.push_back(value);
    3644           0 : }
    3645             : 
    3646             : /** \brief Push a Double zero on the stack.
    3647             :  *
    3648             :  * This function pushes a double on the stack. The double is set to 0.0.
    3649             :  */
    3650           0 : void inst_push_double_zero()
    3651             : {
    3652             : #if QDOM_XPATH_VERIFICATION
    3653             :     // verify instruction location
    3654           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PUSH_DOUBLE_ZERO)
    3655             :     {
    3656           0 :         throw QDomXPathException_InternalError("INST_PUSH_DOUBLE_ZERO not at the right location in the table of instructions");
    3657             :     }
    3658             : #endif
    3659           0 :     variant_t value;
    3660           0 :     double zero(0.0);
    3661           0 :     value.atomic_value_t::setValue(zero);
    3662           0 :     f_functions.back().f_stack.push_back(value);
    3663           0 : }
    3664             : 
    3665             : 
    3666             : /** \brief Add one to the number at the top of the stack.
    3667             :  *
    3668             :  * This function pops one integer, adds one to it, and push it back.
    3669             :  * Note that one is added even to single and double numbers, and not
    3670             :  * epsilon. This means really large numbers will not change.
    3671             :  *
    3672             :  * Only integers, decimal, single, and doubles can be added between
    3673             :  * each others.
    3674             :  */
    3675           0 : void inst_increment()
    3676             : {
    3677             : #if QDOM_XPATH_VERIFICATION
    3678             :     // verify instruction location
    3679           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_INCREMENT)
    3680             :     {
    3681           0 :         throw QDomXPathException_InternalError("INST_INCREMENT not at the right location in the table of instructions");
    3682             :     }
    3683             : #endif
    3684           0 :     variant_t value(pop_variant_data());
    3685           0 :     switch(value.getType())
    3686             :     {
    3687           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    3688           0 :         value.atomic_value_t::setValue(value.getIntegerValue() + 1);
    3689           0 :         break;
    3690             : 
    3691           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    3692           0 :         value.atomic_value_t::setValue(value.getSingleValue(true) + 1.0f);
    3693           0 :         break;
    3694             : 
    3695           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    3696           0 :         value.atomic_value_t::setValue(value.getDoubleValue(true) + 1.0);
    3697           0 :         break;
    3698             : 
    3699           0 :     default:
    3700           0 :         throw QDomXPathException_WrongType("the '++' operator cannot be used with the left and right hand side types");
    3701             : 
    3702             :     }
    3703           0 :     f_functions.back().f_stack.push_back(value);
    3704           0 : }
    3705             : 
    3706             : 
    3707             : /** \brief Subtract one to the number at the top of the stack.
    3708             :  *
    3709             :  * This function pops one integer, subtracts one to it, and push it back.
    3710             :  * Note that one is subtracted even to single and double numbers, and not
    3711             :  * epsilon. This means really large numbers will not change.
    3712             :  *
    3713             :  * Only integers, decimal, single, and doubles can be added between
    3714             :  * each others.
    3715             :  */
    3716           0 : void inst_decrement()
    3717             : {
    3718             : #if QDOM_XPATH_VERIFICATION
    3719             :     // verify instruction location
    3720           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DECREMENT)
    3721             :     {
    3722           0 :         throw QDomXPathException_InternalError("INST_DECREMENT not at the right location in the table of instructions");
    3723             :     }
    3724             : #endif
    3725           0 :     variant_t value(pop_variant_data());
    3726           0 :     switch(value.getType())
    3727             :     {
    3728           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    3729           0 :         value.atomic_value_t::setValue(value.getIntegerValue() + 1);
    3730           0 :         break;
    3731             : 
    3732           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    3733           0 :         value.atomic_value_t::setValue(value.getSingleValue(true) + 1);
    3734           0 :         break;
    3735             : 
    3736           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    3737           0 :         value.atomic_value_t::setValue(value.getDoubleValue(true) + 1);
    3738           0 :         break;
    3739             : 
    3740           0 :     default:
    3741           0 :         throw QDomXPathException_WrongType("the '--' operator cannot be used with the left and right hand side types");
    3742             : 
    3743             :     }
    3744           0 :     f_functions.back().f_stack.push_back(value);
    3745           0 : }
    3746             : 
    3747             : 
    3748             : /** \brief Return the length of a string in characters.
    3749             :  *
    3750             :  * This function pops a string from the stack, computes its length in
    3751             :  * characters, and pushes that length back on the stack.
    3752             :  */
    3753           0 : void inst_string_length()
    3754             : {
    3755             : #if QDOM_XPATH_VERIFICATION
    3756             :     // verify instruction location
    3757           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_STRING_LENGTH)
    3758             :     {
    3759           0 :         throw QDomXPathException_InternalError("INST_STRING_LENGTH not at the right location in the table of instructions");
    3760             :     }
    3761             : #endif
    3762           0 :     variant_t value(pop_variant_data());
    3763           0 :     if(value.getType() != atomic_value_t::type_t::ATOMIC_TYPE_STRING)
    3764             :     {
    3765           0 :         throw QDomXPathException_WrongType("the string-length() function only accepts strings");
    3766             :     }
    3767           0 :     value.atomic_value_t::setValue(static_cast<int64_t>(value.getStringValue().length()));
    3768             : 
    3769           0 :     f_functions.back().f_stack.push_back(value);
    3770           0 : }
    3771             : 
    3772             : 
    3773             : /** \brief Compute the ceiling of a number.
    3774             :  *
    3775             :  * This function pops one number. If the number is an integer, then it pushes
    3776             :  * it back as is. If the number if a Decimal, a Single, or a Double, it
    3777             :  * checks the decimal digits. If all are zeroes, then the same value is
    3778             :  * pushed back on the stack. Otherwise it resets all the decimal digits
    3779             :  * adds one and then push the result back on the stack as the same type.
    3780             :  *
    3781             :  * \note
    3782             :  * This function does not yet handle NaN numbers.
    3783             :  *
    3784             :  * \note
    3785             :  * The value is NOT transformed to an integer. The cast needs to be used
    3786             :  * for that purpose.
    3787             :  */
    3788           0 : void inst_ceiling()
    3789             : {
    3790             : #if QDOM_XPATH_VERIFICATION
    3791             :     // verify instruction location
    3792           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_CEILING)
    3793             :     {
    3794           0 :         throw QDomXPathException_InternalError("INST_CEILING not at the right location in the table of instructions");
    3795             :     }
    3796             : #endif
    3797           0 :     variant_t value(pop_variant_data());
    3798           0 :     switch(value.getType())
    3799             :     {
    3800           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    3801             :         // nothing happens
    3802           0 :         break;
    3803             : 
    3804           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    3805           0 :         value.atomic_value_t::setValue(std::ceil(value.getSingleValue()));
    3806           0 :         break;
    3807             : 
    3808           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    3809           0 :         value.atomic_value_t::setValue(std::ceil(value.getDoubleValue()));
    3810           0 :         break;
    3811             : 
    3812           0 :     default:
    3813           0 :         throw QDomXPathException_WrongType("the ceiling() function can only be applied against numbers");
    3814             : 
    3815             :     }
    3816             : 
    3817           0 :     f_functions.back().f_stack.push_back(value);
    3818           0 : }
    3819             : 
    3820             : 
    3821             : /** \brief Compute the floor of a number.
    3822             :  *
    3823             :  * This function pops one number. If the number is an integer, then it pushes
    3824             :  * it back as is. If the number if a Decimal, a Single, or a Double, it
    3825             :  * sets all of its decimal digits to zero and pushes that back on the
    3826             :  * same as the same type.
    3827             :  *
    3828             :  * \note
    3829             :  * This function does not yet handle NaN numbers.
    3830             :  *
    3831             :  * \note
    3832             :  * The value is NOT transformed to an integer. The cast needs to be used
    3833             :  * for that purpose.
    3834             :  */
    3835           0 : void inst_floor()
    3836             : {
    3837             : #if QDOM_XPATH_VERIFICATION
    3838             :     // verify instruction location
    3839           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_FLOOR)
    3840             :     {
    3841           0 :         throw QDomXPathException_InternalError("INST_FLOOR not at the right location in the table of instructions");
    3842             :     }
    3843             : #endif
    3844           0 :     variant_t value(pop_variant_data());
    3845           0 :     switch(value.getType())
    3846             :     {
    3847           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    3848             :         // nothing happens
    3849           0 :         break;
    3850             : 
    3851           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    3852           0 :         value.atomic_value_t::setValue(std::floor(value.getSingleValue()));
    3853           0 :         break;
    3854             : 
    3855           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    3856           0 :         value.atomic_value_t::setValue(std::floor(value.getDoubleValue()));
    3857           0 :         break;
    3858             : 
    3859           0 :     default:
    3860           0 :         throw QDomXPathException_WrongType("the floor() function can only be applied against numbers");
    3861             : 
    3862             :     }
    3863             : 
    3864           0 :     f_functions.back().f_stack.push_back(value);
    3865           0 : }
    3866             : 
    3867             : 
    3868             : /** \brief Compute the rounded value of a number.
    3869             :  *
    3870             :  * This function pops one number. If the number is an integer, then it pushes
    3871             :  * it back as is. If the number if a Decimal, a Single, or a Double, then
    3872             :  * the function adds 0.5 and then it computes the floor() (the floor
    3873             :  * sets all the decimal digits of the result to zeroes.)
    3874             :  *
    3875             :  * The result is pushed back on the stack as the same type as the input.
    3876             :  *
    3877             :  * \note
    3878             :  * Numbers such as -0.8 are expected to return -0.0 which this function
    3879             :  * does not do.
    3880             :  *
    3881             :  * \note
    3882             :  * This function does not yet handle NaN numbers.
    3883             :  *
    3884             :  * \note
    3885             :  * The value is NOT transformed to an integer. The cast needs to be used
    3886             :  * for that purpose.
    3887             :  */
    3888           0 : void inst_round()
    3889             : {
    3890             : #if QDOM_XPATH_VERIFICATION
    3891             :     // verify instruction location
    3892           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_ROUND)
    3893             :     {
    3894           0 :         throw QDomXPathException_InternalError("INST_ROUND not at the right location in the table of instructions");
    3895             :     }
    3896             : #endif
    3897           0 :     variant_t value(pop_variant_data());
    3898           0 :     switch(value.getType())
    3899             :     {
    3900           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    3901             :         // nothing happens
    3902           0 :         break;
    3903             : 
    3904           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    3905           0 :         value.atomic_value_t::setValue(std::floor(value.getSingleValue() + 0.5f));
    3906           0 :         break;
    3907             : 
    3908           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    3909           0 :         value.atomic_value_t::setValue(std::floor(value.getDoubleValue() + 0.5));
    3910           0 :         break;
    3911             : 
    3912           0 :     default:
    3913           0 :         throw QDomXPathException_WrongType("the round() function can only be applied against numbers");
    3914             : 
    3915             :     }
    3916             : 
    3917           0 :     f_functions.back().f_stack.push_back(value);
    3918           0 : }
    3919             : 
    3920             : 
    3921             : /** \brief Add two numbers together.
    3922             :  *
    3923             :  * This function adds two values that it first pops from the stack.
    3924             :  * The add differs slightly depending on the type of each value.
    3925             :  *
    3926             :  * Only integers, decimal, single, and doubles can be added between
    3927             :  * each others.
    3928             :  */
    3929           0 : void inst_add()
    3930             : {
    3931             : #if QDOM_XPATH_VERIFICATION
    3932             :     // verify instruction location
    3933           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_ADD)
    3934             :     {
    3935           0 :         throw QDomXPathException_InternalError("INST_ADD not at the right location in the table of instructions");
    3936             :     }
    3937             : #endif
    3938           0 :     variant_t rhs(pop_variant_data());
    3939           0 :     variant_t lhs(pop_variant_data());
    3940           0 :     variant_t result;
    3941           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    3942             :     {
    3943           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    3944           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() + rhs.getIntegerValue());
    3945           0 :         break;
    3946             : 
    3947           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    3948             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    3949             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    3950           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) + rhs.getSingleValue(true));
    3951           0 :         break;
    3952             : 
    3953           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    3954             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    3955             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    3956             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    3957             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    3958           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) + rhs.getDoubleValue(true));
    3959           0 :         break;
    3960             : 
    3961           0 :     default:
    3962           0 :         throw QDomXPathException_WrongType("the '+' operator cannot be used with the left and right hand side types");
    3963             : 
    3964             :     }
    3965           0 :     f_functions.back().f_stack.push_back(result);
    3966           0 : }
    3967             : 
    3968             : 
    3969             : /** \brief Subtract two numbers from each others.
    3970             :  *
    3971             :  * This function subtract two values that it first pops from the stack.
    3972             :  * The subtract differs slightly depending on the type of each value.
    3973             :  *
    3974             :  * Only integers, decimal, single, and doubles can be subtracted from
    3975             :  * each others.
    3976             :  */
    3977           0 : void inst_subtract()
    3978             : {
    3979             : #if QDOM_XPATH_VERIFICATION
    3980             :     // verify instruction location
    3981           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SUBTRACT)
    3982             :     {
    3983           0 :         throw QDomXPathException_InternalError("INST_SUBTRACT not at the right location in the table of instructions");
    3984             :     }
    3985             : #endif
    3986           0 :     variant_t rhs(pop_variant_data());
    3987           0 :     variant_t lhs(pop_variant_data());
    3988           0 :     variant_t result;
    3989           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    3990             :     {
    3991           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    3992           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() - rhs.getIntegerValue());
    3993           0 :         break;
    3994             : 
    3995           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    3996             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    3997             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    3998           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) - rhs.getSingleValue(true));
    3999           0 :         break;
    4000             : 
    4001           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4002             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4003             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4004             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4005             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4006           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) - rhs.getDoubleValue(true));
    4007           0 :         break;
    4008             : 
    4009           0 :     default:
    4010           0 :         throw QDomXPathException_WrongType("the '-' operator cannot be used with the left and right hand side types");
    4011             : 
    4012             :     }
    4013           0 :     f_functions.back().f_stack.push_back(result);
    4014           0 : }
    4015             : 
    4016             : 
    4017             : /** \brief Negate a number.
    4018             :  *
    4019             :  * This function pops a number negates it and push it back on the stack.
    4020             :  *
    4021             :  * Only integers, decimal, single, and doubles can be negated from
    4022             :  * each others.
    4023             :  */
    4024           0 : void inst_negate()
    4025             : {
    4026             : #if QDOM_XPATH_VERIFICATION
    4027             :     // verify instruction location
    4028           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_NEGATE)
    4029             :     {
    4030           0 :         throw QDomXPathException_InternalError("INST_NEGATE not at the right location in the table of instructions");
    4031             :     }
    4032             : #endif
    4033           0 :     variant_t value(pop_variant_data());
    4034           0 :     variant_t result;
    4035           0 :     switch(value.getType())
    4036             :     {
    4037           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    4038           0 :         result.atomic_value_t::setValue(-value.getIntegerValue());
    4039           0 :         break;
    4040             : 
    4041           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    4042           0 :         result.atomic_value_t::setValue(-value.getSingleValue());
    4043           0 :         break;
    4044             : 
    4045           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    4046           0 :         result.atomic_value_t::setValue(-value.getDoubleValue());
    4047           0 :         break;
    4048             : 
    4049           0 :     default:
    4050           0 :         throw QDomXPathException_WrongType("the '-' operator cannot be used with this value type");
    4051             : 
    4052             :     }
    4053           0 :     f_functions.back().f_stack.push_back(result);
    4054           0 : }
    4055             : 
    4056             : 
    4057             : /** \brief Multiply two numbers from each others.
    4058             :  *
    4059             :  * This function multiplies two values that it first pops from the stack.
    4060             :  * The multiply differs slightly depending on the type of each value.
    4061             :  *
    4062             :  * Only integers, decimal, single, and doubles can be subtracted from
    4063             :  * each others.
    4064             :  */
    4065           0 : void inst_multiply()
    4066             : {
    4067             : #if QDOM_XPATH_VERIFICATION
    4068             :     // verify instruction location
    4069           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_MULTIPLY)
    4070             :     {
    4071           0 :         throw QDomXPathException_InternalError("INST_MULTIPLY not at the right location in the table of instructions");
    4072             :     }
    4073             : #endif
    4074           0 :     variant_t rhs(pop_variant_data());
    4075           0 :     variant_t lhs(pop_variant_data());
    4076           0 :     variant_t result;
    4077           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4078             :     {
    4079           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4080           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() * rhs.getIntegerValue());
    4081           0 :         break;
    4082             : 
    4083           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4084             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4085             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4086           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) * rhs.getSingleValue(true));
    4087           0 :         break;
    4088             : 
    4089           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4090             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4091             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4092             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4093             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4094           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) * rhs.getDoubleValue(true));
    4095           0 :         break;
    4096             : 
    4097           0 :     default:
    4098           0 :         throw QDomXPathException_WrongType("the '*' operator cannot be used with the left and right hand side types");
    4099             : 
    4100             :     }
    4101           0 :     f_functions.back().f_stack.push_back(result);
    4102           0 : }
    4103             : 
    4104             : 
    4105             : /** \brief Divide two numbers from each others.
    4106             :  *
    4107             :  * This function divides two values that it first pops from the stack.
    4108             :  * The divide differs slightly depending on the type of each value.
    4109             :  * Note that dividing two integers generates a double as the result.
    4110             :  *
    4111             :  * Only integers, decimal, single, and doubles can be subtracted from
    4112             :  * each others.
    4113             :  */
    4114           0 : void inst_divide()
    4115             : {
    4116             : #if QDOM_XPATH_VERIFICATION
    4117             :     // verify instruction location
    4118           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_DIVIDE)
    4119             :     {
    4120           0 :         throw QDomXPathException_InternalError("INST_DIVIDE not at the right location in the table of instructions");
    4121             :     }
    4122             : #endif
    4123           0 :     variant_t rhs(pop_variant_data());
    4124           0 :     variant_t lhs(pop_variant_data());
    4125           0 :     variant_t result;
    4126           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4127             :     {
    4128           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4129           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) / rhs.getDoubleValue(true));
    4130           0 :         break;
    4131             : 
    4132           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4133             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4134             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4135           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) / rhs.getSingleValue(true));
    4136           0 :         break;
    4137             : 
    4138           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4139             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4140             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4141             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4142             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4143           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) / rhs.getDoubleValue(true));
    4144           0 :         break;
    4145             : 
    4146           0 :     default:
    4147           0 :         throw QDomXPathException_WrongType("the 'div' operator cannot be used with the left and right hand side types");
    4148             : 
    4149             :     }
    4150           0 :     f_functions.back().f_stack.push_back(result);
    4151           0 : }
    4152             : 
    4153             : 
    4154             : /** \brief Divide two numbers as integers.
    4155             :  *
    4156             :  * This function divides two values that it first pops from the stack.
    4157             :  * The divide transforms the left and right hand side numbers to integers
    4158             :  * before performing the division and the result is always an integer.
    4159             :  *
    4160             :  * Only integers, decimal, single, and doubles can be subtracted from
    4161             :  * each others.
    4162             :  */
    4163           0 : void inst_idivide()
    4164             : {
    4165             : #if QDOM_XPATH_VERIFICATION
    4166             :     // verify instruction location
    4167           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_IDIVIDE)
    4168             :     {
    4169           0 :         throw QDomXPathException_InternalError("INST_IDIVIDE not at the right location in the table of instructions");
    4170             :     }
    4171             : #endif
    4172           0 :     variant_t rhs(pop_variant_data());
    4173           0 :     int64_t const right_value(rhs.getIntegerValue(true));
    4174           0 :     if(right_value == 0)
    4175             :     {
    4176           0 :         throw QDomXPathException_DivisionByZero("the 'idiv' operator cannot be used with the left and right hand side types");
    4177             :     }
    4178           0 :     variant_t lhs(pop_variant_data());
    4179           0 :     variant_t result;
    4180           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4181             :     {
    4182           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4183             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4184             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4185             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4186             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4187             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4188             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4189             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4190             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4191           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue(true) / right_value);
    4192           0 :         break;
    4193             : 
    4194           0 :     default:
    4195           0 :         throw QDomXPathException_WrongType("the 'idiv' operator cannot be used with the left and right hand side types");
    4196             : 
    4197             :     }
    4198           0 :     f_functions.back().f_stack.push_back(result);
    4199           0 : }
    4200             : 
    4201             : 
    4202             : /** \brief Compute the modulo of two numbers from each others.
    4203             :  *
    4204             :  * This function computes the modulo of two number that it first pops
    4205             :  * from the stack. The modulo differs slightly depending on the type of
    4206             :  * each value.
    4207             :  *
    4208             :  * Only integers, decimal, single, and doubles can be subtracted from
    4209             :  * each others.
    4210             :  */
    4211           0 : void inst_modulo()
    4212             : {
    4213             : #if QDOM_XPATH_VERIFICATION
    4214             :     // verify instruction location
    4215           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_MODULO)
    4216             :     {
    4217           0 :         throw QDomXPathException_InternalError("INST_MODULO not at the right location in the table of instructions");
    4218             :     }
    4219             : #endif
    4220           0 :     variant_t rhs(pop_variant_data());
    4221           0 :     variant_t lhs(pop_variant_data());
    4222           0 :     variant_t result;
    4223           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4224             :     {
    4225           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4226           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() % rhs.getIntegerValue());
    4227           0 :         break;
    4228             : 
    4229           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4230             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4231             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4232           0 :         result.atomic_value_t::setValue(std::fmod(lhs.getSingleValue(true), rhs.getSingleValue(true)));
    4233           0 :         break;
    4234             : 
    4235           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4236             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4237             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4238             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4239             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4240           0 :         result.atomic_value_t::setValue(std::fmod(lhs.getDoubleValue(true), rhs.getDoubleValue(true)));
    4241           0 :         break;
    4242             : 
    4243           0 :     default:
    4244           0 :         throw QDomXPathException_WrongType("the 'mod' operator cannot be used with the left and right hand side types");
    4245             : 
    4246             :     }
    4247           0 :     f_functions.back().f_stack.push_back(result);
    4248           0 : }
    4249             : 
    4250             : 
    4251             : /** \brief Inverse a Boolean.
    4252             :  *
    4253             :  * This function pops a Boolean value and returns the opposite Boolean
    4254             :  * (so true becomes false and vice versa.)
    4255             :  *
    4256             :  * Only Boolean are accepted by this operator.
    4257             :  */
    4258           0 : void inst_not()
    4259             : {
    4260             : #if QDOM_XPATH_VERIFICATION
    4261             :     // verify instruction location
    4262           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_NOT)
    4263             :     {
    4264           0 :         throw QDomXPathException_InternalError("INST_NOT not at the right location in the table of instructions");
    4265             :     }
    4266             : #endif
    4267           0 :     variant_t boolean(pop_variant_data());
    4268           0 :     if(boolean.getType() != atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN)
    4269             :     {
    4270           0 :         throw QDomXPathException_WrongType("the Not operator can only be applied against a Boolean value");
    4271             :     }
    4272           0 :     boolean.atomic_value_t::setValue(!boolean.atomic_value_t::getBooleanValue());
    4273             : 
    4274           0 :     f_functions.back().f_stack.push_back(boolean);
    4275           0 : }
    4276             : 
    4277             : 
    4278             : /** \brief Compute the multiplication of two Booleans.
    4279             :  *
    4280             :  * This function pops two Boolean values and returns the AND operation
    4281             :  * (i.e. Boolean multiplication) so if both sides are true, it pushes
    4282             :  * true back on the stack. In all other cases it pushes false.
    4283             :  *
    4284             :  * Only Boolean are accepted by this operator.
    4285             :  */
    4286           0 : void inst_and()
    4287             : {
    4288             : #if QDOM_XPATH_VERIFICATION
    4289             :     // verify instruction location
    4290           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_AND)
    4291             :     {
    4292           0 :         throw QDomXPathException_InternalError("INST_AND not at the right location in the table of instructions");
    4293             :     }
    4294             : #endif
    4295           0 :     variant_t rhs(pop_variant_data());
    4296           0 :     variant_t lhs(pop_variant_data());
    4297           0 :     if(lhs.getType() != atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN
    4298           0 :     || rhs.getType() != atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN)
    4299             :     {
    4300           0 :         throw QDomXPathException_WrongType("the And operator can only be applied against Boolean values");
    4301             :     }
    4302           0 :     variant_t result;
    4303           0 :     result.atomic_value_t::setValue(lhs.atomic_value_t::getBooleanValue() && rhs.atomic_value_t::getBooleanValue());
    4304             : 
    4305           0 :     f_functions.back().f_stack.push_back(result);
    4306           0 : }
    4307             : 
    4308             : 
    4309             : /** \brief Compute the addition of two Booleans.
    4310             :  *
    4311             :  * This function pops two Boolean values and returns the OR operation
    4312             :  * (i.e. Boolean addition) so if either sides is true, it pushes
    4313             :  * true back on the stack. In all other cases it pushes false.
    4314             :  *
    4315             :  * Only Boolean are accepted by this operator.
    4316             :  */
    4317           0 : void inst_or()
    4318             : {
    4319             : #if QDOM_XPATH_VERIFICATION
    4320             :     // verify instruction location
    4321           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_OR)
    4322             :     {
    4323           0 :         throw QDomXPathException_InternalError("INST_OR not at the right location in the table of instructions");
    4324             :     }
    4325             : #endif
    4326           0 :     variant_t rhs(pop_variant_data());
    4327           0 :     variant_t lhs(pop_variant_data());
    4328           0 :     if(lhs.getType() != atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN
    4329           0 :     || rhs.getType() != atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN)
    4330             :     {
    4331           0 :         throw QDomXPathException_WrongType("the Or operator can only be applied against Boolean values");
    4332             :     }
    4333           0 :     variant_t result;
    4334           0 :     result.atomic_value_t::setValue(lhs.atomic_value_t::getBooleanValue() || rhs.atomic_value_t::getBooleanValue());
    4335             : 
    4336           0 :     f_functions.back().f_stack.push_back(result);
    4337           0 : }
    4338             : 
    4339             : 
    4340             : /** \brief Check whether two values are equal.
    4341             :  *
    4342             :  * This function compares the two top-most values from the stack.
    4343             :  * The result is pushed back on the stack.
    4344             :  *
    4345             :  * The comparison process depends on the type of data being compared.
    4346             :  */
    4347           0 : void inst_equal()
    4348             : {
    4349             : #if QDOM_XPATH_VERIFICATION
    4350             :     // verify instruction location
    4351           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_EQUAL)
    4352             :     {
    4353           0 :         throw QDomXPathException_InternalError("INST_EQUAL not at the right location in the table of instructions");
    4354             :     }
    4355             : #endif
    4356           0 :     variant_t rhs(pop_variant_data());
    4357           0 :     variant_t lhs(pop_variant_data());
    4358           0 :     variant_t result;
    4359           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4360             :     {
    4361           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4362           0 :         result.atomic_value_t::setValue(lhs.atomic_value_t::getBooleanValue() == rhs.atomic_value_t::getBooleanValue());
    4363           0 :         break;
    4364             : 
    4365           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4366           0 :         result.atomic_value_t::setValue(lhs.atomic_value_t::getIntegerValue() == rhs.atomic_value_t::getIntegerValue());
    4367           0 :         break;
    4368             : 
    4369           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4370             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4371             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4372           0 :         result.atomic_value_t::setValue(snap::compare_floats(lhs.atomic_value_t::getSingleValue(true), rhs.atomic_value_t::getSingleValue(true)));
    4373           0 :         break;
    4374             : 
    4375           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4376             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4377             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4378             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4379             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4380           0 :         result.atomic_value_t::setValue(snap::compare_floats(lhs.atomic_value_t::getDoubleValue(true), rhs.atomic_value_t::getDoubleValue(true)));
    4381           0 :         break;
    4382             : 
    4383           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING,   atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4384             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4385             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING,   atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET):
    4386             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET, atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET):
    4387             :         try
    4388             :         {
    4389           0 :             result.atomic_value_t::setValue(lhs.getStringValue(true) == rhs.getStringValue(true));
    4390             :         }
    4391           0 :         catch(QDomXPathException_NotImplemented const&)
    4392             :         {
    4393           0 :             result.atomic_value_t::setValue(false);
    4394             :         }
    4395           0 :         break;
    4396             : 
    4397           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4398           0 :         result.atomic_value_t::setValue(true);
    4399           0 :         break;
    4400             : 
    4401           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4402             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4403             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4404             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4405             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4406             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING,  atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4407             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4408             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4409             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4410             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING,  atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4411             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4412             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4413             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4414             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4415             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4416             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4417             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4418             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4419           0 :         result.atomic_value_t::setValue(false);
    4420           0 :         break;
    4421             : 
    4422           0 :     default:
    4423           0 :         throw QDomXPathException_WrongType("the '=' operator cannot be used with the left and right hand side types");
    4424             : 
    4425             :     }
    4426           0 :     f_functions.back().f_stack.push_back(result);
    4427           0 : }
    4428             : 
    4429             : 
    4430             : /** \brief Check whether two values are not equal.
    4431             :  *
    4432             :  * This function compares the two top-most values from the stack.
    4433             :  * The result is pushed back on the stack.
    4434             :  *
    4435             :  * Note that not-equal is not the same as not(equal). Some data may be at
    4436             :  * the same time equal and not equal or neither.
    4437             :  */
    4438           0 : void inst_not_equal()
    4439             : {
    4440             : #if QDOM_XPATH_VERIFICATION
    4441             :     // verify instruction location
    4442           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_NOT_EQUAL)
    4443             :     {
    4444           0 :         throw QDomXPathException_InternalError("INST_NOT_EQUAL not at the right location in the table of instructions");
    4445             :     }
    4446             : #endif
    4447           0 :     variant_t rhs(pop_variant_data());
    4448           0 :     variant_t lhs(pop_variant_data());
    4449           0 :     variant_t result;
    4450           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4451             :     {
    4452           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4453           0 :         result.atomic_value_t::setValue(lhs.getBooleanValue() != rhs.getBooleanValue());
    4454           0 :         break;
    4455             : 
    4456           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4457           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() != rhs.getIntegerValue());
    4458           0 :         break;
    4459             : 
    4460           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4461             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4462             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4463           0 :         result.atomic_value_t::setValue(snap::compare_floats(lhs.getSingleValue(true), rhs.getSingleValue(true)));
    4464           0 :         break;
    4465             : 
    4466           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4467             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4468             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4469             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4470             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4471           0 :         result.atomic_value_t::setValue(snap::compare_floats(lhs.getDoubleValue(true), rhs.getDoubleValue(true)));
    4472           0 :         break;
    4473             : 
    4474           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4475           0 :         result.atomic_value_t::setValue(lhs.getStringValue() != rhs.getStringValue());
    4476           0 :         break;
    4477             : 
    4478           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4479           0 :         result.atomic_value_t::setValue(false);
    4480           0 :         break;
    4481             : 
    4482           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4483             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4484             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4485             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4486             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL,    atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4487             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING , atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4488             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4489             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4490             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4491             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING,  atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4492             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4493             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4494             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4495             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4496             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4497             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4498             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4499             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4500           0 :         result.atomic_value_t::setValue(true);
    4501           0 :         break;
    4502             : 
    4503           0 :     default:
    4504           0 :         throw QDomXPathException_WrongType("the '!=' operator cannot be used with the left and right hand side types");
    4505             : 
    4506             :     }
    4507           0 :     f_functions.back().f_stack.push_back(result);
    4508           0 : }
    4509             : 
    4510             : 
    4511             : /** \brief Check whether two values are ordered.
    4512             :  *
    4513             :  * This function compares the two top-most values on the stack.
    4514             :  * The result is pushed back on the stack.
    4515             :  */
    4516           0 : void inst_less_than()
    4517             : {
    4518             : #if QDOM_XPATH_VERIFICATION
    4519             :     // verify instruction location
    4520           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_LESS_THAN)
    4521             :     {
    4522           0 :         throw QDomXPathException_InternalError("INST_LESS_THAN not at the right location in the table of instructions");
    4523             :     }
    4524             : #endif
    4525           0 :     variant_t rhs(pop_variant_data());
    4526           0 :     variant_t lhs(pop_variant_data());
    4527           0 :     variant_t result;
    4528           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4529             :     {
    4530           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4531           0 :         result.atomic_value_t::setValue(lhs.getBooleanValue() < rhs.getBooleanValue());
    4532           0 :         break;
    4533             : 
    4534           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4535           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() < rhs.getIntegerValue());
    4536           0 :         break;
    4537             : 
    4538           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4539             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4540             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4541           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) < rhs.getSingleValue(true));
    4542           0 :         break;
    4543             : 
    4544           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4545             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4546             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4547             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4548             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4549           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) < rhs.getDoubleValue(true));
    4550           0 :         break;
    4551             : 
    4552           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4553           0 :         result.atomic_value_t::setValue(lhs.getStringValue() < rhs.getStringValue());
    4554           0 :         break;
    4555             : 
    4556           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4557           0 :         result.atomic_value_t::setValue(false);
    4558           0 :         break;
    4559             : 
    4560           0 :     default:
    4561           0 :         throw QDomXPathException_WrongType("the '<' operator cannot be used with the left and right hand side types");
    4562             : 
    4563             :     }
    4564           0 :     f_functions.back().f_stack.push_back(result);
    4565           0 : }
    4566             : 
    4567             : 
    4568             : /** \brief Check whether two values are ordered.
    4569             :  *
    4570             :  * This function compares the two top-most values on the stack.
    4571             :  * The result is pushed back on the stack.
    4572             :  */
    4573           0 : void inst_less_or_equal()
    4574             : {
    4575             : #if QDOM_XPATH_VERIFICATION
    4576             :     // verify instruction location
    4577           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_LESS_OR_EQUAL)
    4578             :     {
    4579           0 :         throw QDomXPathException_InternalError("INST_LESS_OR_EQUAL not at the right location in the table of instructions");
    4580             :     }
    4581             : #endif
    4582           0 :     variant_t rhs(pop_variant_data());
    4583           0 :     variant_t lhs(pop_variant_data());
    4584           0 :     variant_t result;
    4585           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4586             :     {
    4587           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4588           0 :         result.atomic_value_t::setValue(lhs.getBooleanValue() <= rhs.getBooleanValue());
    4589           0 :         break;
    4590             : 
    4591           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4592           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() <= rhs.getIntegerValue());
    4593           0 :         break;
    4594             : 
    4595           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4596             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4597             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4598           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) <= rhs.getSingleValue(true));
    4599           0 :         break;
    4600             : 
    4601           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4602             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4603             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4604             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4605             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4606           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) <= rhs.getDoubleValue(true));
    4607           0 :         break;
    4608             : 
    4609           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4610           0 :         result.atomic_value_t::setValue(lhs.getStringValue() <= rhs.getStringValue());
    4611           0 :         break;
    4612             : 
    4613           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4614           0 :         result.atomic_value_t::setValue(true);
    4615           0 :         break;
    4616             : 
    4617           0 :     default:
    4618           0 :         throw QDomXPathException_WrongType("the '<=' operator cannot be used with the left and right hand side types");
    4619             : 
    4620             :     }
    4621           0 :     f_functions.back().f_stack.push_back(result);
    4622           0 : }
    4623             : 
    4624             : 
    4625             : /** \brief Check whether two values are ordered.
    4626             :  *
    4627             :  * This function compares the two top-most values on the stack.
    4628             :  * The result is pushed back on the stack.
    4629             :  */
    4630           0 : void inst_greater_than()
    4631             : {
    4632             : #if QDOM_XPATH_VERIFICATION
    4633             :     // verify instruction location
    4634           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GREATER_THAN)
    4635             :     {
    4636           0 :         throw QDomXPathException_InternalError("INST_GREATER_THAN not at the right location in the table of instructions");
    4637             :     }
    4638             : #endif
    4639           0 :     variant_t rhs(pop_variant_data());
    4640           0 :     variant_t lhs(pop_variant_data());
    4641           0 :     variant_t result;
    4642           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4643             :     {
    4644           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4645           0 :         result.atomic_value_t::setValue(lhs.getBooleanValue() > rhs.getBooleanValue());
    4646           0 :         break;
    4647             : 
    4648           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4649           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() > rhs.getIntegerValue());
    4650           0 :         break;
    4651             : 
    4652           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4653             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4654             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4655           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) > rhs.getSingleValue(true));
    4656           0 :         break;
    4657             : 
    4658           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4659             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4660             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4661             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4662             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4663           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) > rhs.getDoubleValue(true));
    4664           0 :         break;
    4665             : 
    4666           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4667           0 :         result.atomic_value_t::setValue(lhs.getStringValue() > rhs.getStringValue());
    4668           0 :         break;
    4669             : 
    4670           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4671           0 :         result.atomic_value_t::setValue(false);
    4672           0 :         break;
    4673             : 
    4674           0 :     default:
    4675           0 :         throw QDomXPathException_WrongType("the '>' operator cannot be used with the left and right hand side types");
    4676             : 
    4677             :     }
    4678           0 :     f_functions.back().f_stack.push_back(result);
    4679           0 : }
    4680             : 
    4681             : 
    4682             : /** \brief Check whether two values are ordered.
    4683             :  *
    4684             :  * This function compares the two top-most values on the stack.
    4685             :  * The result is pushed back on the stack.
    4686             :  */
    4687           0 : void inst_greater_or_equal()
    4688             : {
    4689             : #if QDOM_XPATH_VERIFICATION
    4690             :     // verify instruction location
    4691           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GREATER_OR_EQUAL)
    4692             :     {
    4693           0 :         throw QDomXPathException_InternalError("INST_GREATER_OR_EQUAL not at the right location in the table of instructions");
    4694             :     }
    4695             : #endif
    4696           0 :     variant_t rhs(pop_variant_data());
    4697           0 :     variant_t lhs(pop_variant_data());
    4698           0 :     variant_t result;
    4699           0 :     switch(merge_types(lhs.getType(), rhs.getType()))
    4700             :     {
    4701           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN, atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN):
    4702           0 :         result.atomic_value_t::setValue(lhs.getBooleanValue() >= rhs.getBooleanValue());
    4703           0 :         break;
    4704             : 
    4705           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4706           0 :         result.atomic_value_t::setValue(lhs.getIntegerValue() >= rhs.getIntegerValue());
    4707           0 :         break;
    4708             : 
    4709           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4710             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4711             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4712           0 :         result.atomic_value_t::setValue(lhs.getSingleValue(true) >= rhs.getSingleValue(true));
    4713           0 :         break;
    4714             : 
    4715           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_INTEGER):
    4716             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_INTEGER, atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4717             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_SINGLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4718             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_SINGLE):
    4719             :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE,  atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE):
    4720           0 :         result.atomic_value_t::setValue(lhs.getDoubleValue(true) >= rhs.getDoubleValue(true));
    4721           0 :         break;
    4722             : 
    4723           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_STRING, atomic_value_t::type_t::ATOMIC_TYPE_STRING):
    4724           0 :         result.atomic_value_t::setValue(lhs.getStringValue() >= rhs.getStringValue());
    4725           0 :         break;
    4726             : 
    4727           0 :     case merge_types(atomic_value_t::type_t::ATOMIC_TYPE_NULL, atomic_value_t::type_t::ATOMIC_TYPE_NULL):
    4728           0 :         result.atomic_value_t::setValue(true);
    4729           0 :         break;
    4730             : 
    4731           0 :     default:
    4732           0 :         throw QDomXPathException_WrongType("the '>=' operator cannot be used with the left and right hand side types");
    4733             : 
    4734             :     }
    4735           0 :     f_functions.back().f_stack.push_back(result);
    4736           0 : }
    4737             : 
    4738             : 
    4739             : /** \brief Get node-set size.
    4740             :  *
    4741             :  * This function pushes the size of the node-set on the stack.
    4742             :  */
    4743           0 : void inst_node_set_size()
    4744             : {
    4745             : #if QDOM_XPATH_VERIFICATION
    4746             :     // verify instruction location
    4747           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_NODE_SET_SIZE)
    4748             :     {
    4749           0 :         throw QDomXPathException_InternalError("INST_NODE_SET_SIZE not at the right location in the table of instructions");
    4750             :     }
    4751             : #endif
    4752           0 :     variant_t value(pop_variant_data());
    4753           0 :     QDomXPath::node_vector_t node_set(value.getNodeSetValue());
    4754           0 :     variant_t result;
    4755           0 :     result.atomic_value_t::setValue(static_cast<int64_t>(node_set.size()));
    4756           0 :     f_functions.back().f_stack.push_back(result);
    4757           0 : }
    4758             : 
    4759             : 
    4760             : /** \brief Append two node-sets or atomic sets together.
    4761             :  *
    4762             :  * This function pops two sets from the stack, append one to the other,
    4763             :  * and pushes the result back on the stack.
    4764             :  */
    4765           0 : void inst_merge_sets()
    4766             : {
    4767             : #if QDOM_XPATH_VERIFICATION
    4768             :     // verify instruction location
    4769           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_MERGE_SETS)
    4770             :     {
    4771           0 :         throw QDomXPathException_InternalError("INST_MERGE_SETS not at the right location in the table of instructions");
    4772             :     }
    4773             : #endif
    4774           0 :     variant_t rhs(pop_variant_data());
    4775           0 :     variant_t lhs(pop_variant_data());
    4776           0 :     if(rhs.getType() == atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET
    4777           0 :     && lhs.getType() == atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET)
    4778             :     {
    4779           0 :         QDomXPath::node_vector_t l(lhs.getNodeSetValue());
    4780           0 :         QDomXPath::node_vector_t r(rhs.getNodeSetValue());
    4781           0 :         const int imax(r.size());
    4782           0 :         for(int i(0); i < imax; ++i)
    4783             :         {
    4784           0 :             l.push_back(r[i]);
    4785             :         }
    4786           0 :         variant_t result;
    4787           0 :         result.setValue(l);
    4788           0 :         f_functions.back().f_stack.push_back(result);
    4789             :     }
    4790           0 :     else if(rhs.getType() == atomic_value_t::type_t::ATOMIC_TYPE_SET
    4791           0 :          && lhs.getType() == atomic_value_t::type_t::ATOMIC_TYPE_SET)
    4792             :     {
    4793           0 :         atomic_vector_t l(lhs.getSetValue());
    4794           0 :         atomic_vector_t r(rhs.getSetValue());
    4795           0 :         const int imax(r.size());
    4796           0 :         for(int i(0); i < imax; ++i)
    4797             :         {
    4798           0 :             l.push_back(r[i]);
    4799             :         }
    4800           0 :         variant_t result;
    4801           0 :         result.setValue(l);
    4802           0 :         f_functions.back().f_stack.push_back(result);
    4803             :     }
    4804             :     else
    4805             :     {
    4806           0 :         throw QDomXPathException_WrongType("the 'union' operator cannot be used with anything else than node sets at this point");
    4807             :     }
    4808           0 : }
    4809             : 
    4810             : 
    4811             : /** \brief Retrieve the current position.
    4812             :  *
    4813             :  * This function pushes the current position of the context node
    4814             :  * on the stack.
    4815             :  */
    4816           0 : void inst_get_position()
    4817             : {
    4818             : #if QDOM_XPATH_VERIFICATION
    4819             :     // verify instruction location
    4820           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GET_POSITION)
    4821             :     {
    4822           0 :         throw QDomXPathException_InternalError("INST_GET_POSITION not at the right location in the table of instructions");
    4823             :     }
    4824             : #endif
    4825           0 :     contexts_not_empty();
    4826           0 :     variant_t result;
    4827           0 :     int64_t position(static_cast<int64_t>(f_functions.back().f_contexts.back().f_position));
    4828           0 :     result.atomic_value_t::setValue(position + 1);
    4829           0 :     f_functions.back().f_stack.push_back(result);
    4830           0 : }
    4831             : 
    4832             : 
    4833             : /** \brief Set the position.
    4834             :  *
    4835             :  * This internal function is used to set the current position. Internally
    4836             :  * we use those to go through the whole list of nodes in a node-set.
    4837             :  */
    4838           0 : void inst_set_position()
    4839             : {
    4840             : #if QDOM_XPATH_VERIFICATION
    4841             :     // verify instruction location
    4842           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SET_POSITION)
    4843             :     {
    4844           0 :         throw QDomXPathException_InternalError("INST_SET_POSITION not at the right location in the table of instructions");
    4845             :     }
    4846             : #endif
    4847           0 :     variant_t position(pop_variant_data());
    4848           0 :     if(position.getType() != atomic_value_t::type_t::ATOMIC_TYPE_INTEGER)
    4849             :     {
    4850           0 :         throw QDomXPathException_WrongType("the 'set_position' operator cannot be used with anything else than an integer as its first operand");
    4851             :     }
    4852           0 :     contexts_not_empty();
    4853           0 :     int p(static_cast<int>(position.getIntegerValue()));
    4854           0 :     if(p < 1 || p > f_functions.back().f_contexts.back().f_nodes.size())
    4855             :     {
    4856           0 :         throw QDomXPathException_OutOfRange("the new position in 'set_position' is out of range");
    4857             :     }
    4858             :     // within XPath position is 1 based
    4859           0 :     f_functions.back().f_contexts.back().f_position = p - 1;
    4860           0 : }
    4861             : 
    4862             : 
    4863             : /** \brief Get the node-set on the stack.
    4864             :  *
    4865             :  * This function retrieves the current node-set from this state.
    4866             :  */
    4867           0 : void inst_get_node_set()
    4868             : {
    4869             : #if QDOM_XPATH_VERIFICATION
    4870             :     // verify instruction location
    4871           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GET_NODE_SET)
    4872             :     {
    4873           0 :         throw QDomXPathException_InternalError("INST_GET_NODE_SET not at the right location in the table of instructions");
    4874             :     }
    4875             : #endif
    4876           0 :     contexts_not_empty();
    4877           0 :     variant_t result;
    4878           0 :     result.setValue(f_functions.back().f_contexts.back().f_nodes);
    4879           0 :     f_functions.back().f_stack.push_back(result);
    4880           0 : }
    4881             : 
    4882             : 
    4883             : /** \brief Set the node-set from the stack.
    4884             :  *
    4885             :  * This function saves the stack node-set as the new node-set of this state.
    4886             :  */
    4887           0 : void inst_set_node_set()
    4888             : {
    4889             : #if QDOM_XPATH_VERIFICATION
    4890             :     // verify instruction location
    4891           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SET_NODE_SET)
    4892             :     {
    4893           0 :         throw QDomXPathException_InternalError("INST_SET_NODE_SET not at the right location in the table of instructions");
    4894             :     }
    4895             : #endif
    4896           0 :     variant_t node_set(pop_variant_data());
    4897           0 :     if(node_set.getType() != atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET)
    4898             :     {
    4899           0 :         throw QDomXPathException_WrongType("the 'set_node_set' operator cannot be used with anything else than a node-set");
    4900             :     }
    4901           0 :     contexts_not_empty();
    4902           0 :     f_functions.back().f_contexts.back().f_nodes = node_set.getNodeSetValue();
    4903           0 : }
    4904             : 
    4905             : 
    4906             : /** \brief Get the result on the stack.
    4907             :  *
    4908             :  * This function retrieves the current result on this state.
    4909             :  */
    4910           0 : void inst_get_result()
    4911             : {
    4912             : #if QDOM_XPATH_VERIFICATION
    4913             :     // verify instruction location
    4914           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GET_RESULT)
    4915             :     {
    4916           0 :         throw QDomXPathException_InternalError("INST_GET_RESULT not at the right location in the table of instructions");
    4917             :     }
    4918             : #endif
    4919           0 :     contexts_not_empty();
    4920           0 :     variant_t result;
    4921           0 :     result.setValue(f_functions.back().f_contexts.back().f_result);
    4922           0 :     f_functions.back().f_stack.push_back(result);
    4923           0 : }
    4924             : 
    4925             : 
    4926             : /** \brief Set the result on the stack.
    4927             :  *
    4928             :  * This function saves the stack node-set as the new result of this state.
    4929             :  */
    4930           0 : void inst_set_result()
    4931             : {
    4932             : #if QDOM_XPATH_VERIFICATION
    4933             :     // verify instruction location
    4934           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_SET_RESULT)
    4935             :     {
    4936           0 :         throw QDomXPathException_InternalError("INST_SET_RESULT not at the right location in the table of instructions");
    4937             :     }
    4938             : #endif
    4939           0 :     variant_t result(pop_variant_data());
    4940           0 :     if(result.getType() != atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET)
    4941             :     {
    4942           0 :         throw QDomXPathException_WrongType("the 'set_result' operator cannot be used with anything else than a node-set");
    4943             :     }
    4944           0 :     contexts_not_empty();
    4945           0 :     f_functions.back().f_contexts.back().f_result = result.getNodeSetValue();
    4946           0 : }
    4947             : 
    4948             : 
    4949             : /** \brief Replace the node-set with the root node.
    4950             :  *
    4951             :  * This function clears the existing node-set and replace it with one
    4952             :  * node: the root node.
    4953             :  */
    4954           0 : void inst_root()
    4955             : {
    4956             : #if QDOM_XPATH_VERIFICATION
    4957             :     // verify instruction location
    4958           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_ROOT)
    4959             :     {
    4960           0 :         throw QDomXPathException_InternalError("INST_ROOT not at the right location in the table of instructions");
    4961             :     }
    4962             : #endif
    4963             :     // if empty then it stays that way
    4964           0 :     stack_not_empty(atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET);
    4965           0 :     QDomXPath::node_vector_t& node_set(f_functions.back().f_stack.back().getNodeSetValue());
    4966           0 :     if(!node_set.isEmpty())
    4967             :     {
    4968           0 :         QDomNode root(node_set[0].ownerDocument());
    4969           0 :         if(root.isElement())
    4970             :         {
    4971             :             // this happens when the node we start with is an attribute
    4972           0 :             root = root.ownerDocument();
    4973             :         }
    4974           0 :         node_set.clear();
    4975           0 :         if(!root.isNull())
    4976             :         {
    4977             :             // ignore null nodes and keep our list empty of them
    4978           0 :             node_set.push_back(root);
    4979             :         }
    4980             :     }
    4981           0 : }
    4982             : 
    4983             : 
    4984             : /** \brief Check the current result as the predicate result.
    4985             :  *
    4986             :  * This function checks the last result on the stack as the result of
    4987             :  * a predicate. If true, the current node is added to the result set.
    4988             :  */
    4989           0 : void inst_predicate()
    4990             : {
    4991             : #if QDOM_XPATH_VERIFICATION
    4992             :     // verify instruction location
    4993           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_PREDICATE)
    4994             :     {
    4995           0 :         throw QDomXPathException_InternalError("INST_PREDICATE not at the right location in the table of instructions");
    4996             :     }
    4997             : #endif
    4998           0 :     bool result(false);
    4999           0 :     variant_t predicate_result(pop_variant_data());
    5000           0 :     switch(predicate_result.getType())
    5001             :     {
    5002           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_BOOLEAN:
    5003             :     case atomic_value_t::type_t::ATOMIC_TYPE_STRING:
    5004             :         // true or false
    5005           0 :         result = predicate_result.getBooleanValue(true);
    5006           0 :         break;
    5007             : 
    5008           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_INTEGER:
    5009             :     case atomic_value_t::type_t::ATOMIC_TYPE_SINGLE:
    5010             :     case atomic_value_t::type_t::ATOMIC_TYPE_DOUBLE:
    5011           0 :         contexts_not_empty();
    5012           0 :         result = predicate_result.getIntegerValue(true) == f_functions.back().f_contexts.back().f_position + 1;
    5013           0 :         break;
    5014             : 
    5015           0 :     case atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET:
    5016             :         {
    5017             :             // for a node set, it is considered true only if not empty
    5018           0 :             QDomXPath::node_vector_t r(predicate_result.getNodeSetValue());
    5019           0 :             result = r.size() != 0;
    5020             :         }
    5021           0 :         break;
    5022             : 
    5023           0 :     default:
    5024             :         // anything else always returns false
    5025             :         //throw QDomXPathException_WrongType(QString("the 'predicate' operator cannot be used with anything else than a node-set (got node of type %1)").arg(static_cast<int>(predicate_result.getType())));
    5026           0 :         break;
    5027             : 
    5028             :     }
    5029             : 
    5030           0 :     context_vector_t::reference context(f_functions.back().f_contexts.back());
    5031           0 :     if(context.f_position != -1
    5032           0 :     && result)
    5033             :     {
    5034           0 :         context.f_result.push_back(context.f_nodes[context.f_position]);
    5035             :     }
    5036             : 
    5037             :     // if +1 to position is too large, just return false
    5038           0 :     const bool has_another_position(context.f_position + 1 < context.f_nodes.size());
    5039           0 :     if(has_another_position)
    5040             :     {
    5041           0 :         ++context.f_position;
    5042             :     }
    5043             : 
    5044           0 :     variant_t value;
    5045           0 :     value.atomic_value_t::setValue(has_another_position);
    5046           0 :     f_functions.back().f_stack.push_back(value);
    5047           0 : }
    5048             : 
    5049             : 
    5050           0 : void inst_create_node_context()
    5051             : {
    5052             : #if QDOM_XPATH_VERIFICATION
    5053             :     // verify instruction location
    5054           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_CREATE_NODE_CONTEXT)
    5055             :     {
    5056           0 :         throw QDomXPathException_InternalError("INST_CREATE_NODE_CONTEXT not at the right location in the table of instructions");
    5057             :     }
    5058             : #endif
    5059           0 :     variant_t node_set(pop_variant_data());
    5060           0 :     if(node_set.getType() != atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET)
    5061             :     {
    5062           0 :         throw QDomXPathException_WrongType("a node set is required to create a node context");
    5063             :     }
    5064           0 :     context_t context;
    5065           0 :     context.f_nodes = node_set.getNodeSetValue();
    5066           0 :     context.f_position = context.f_nodes.empty() ? -1 : 0;
    5067           0 :     f_functions.back().f_contexts.push_back(context);
    5068           0 : }
    5069             : 
    5070             : 
    5071           0 : void inst_next_context_node()
    5072             : {
    5073             : #if QDOM_XPATH_VERIFICATION
    5074             :     // verify instruction location
    5075           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_NEXT_CONTEXT_NODE)
    5076             :     {
    5077           0 :         throw QDomXPathException_InternalError("INST_NEXT_CONTEXT_NODE not at the right location in the table of instructions");
    5078             :     }
    5079             : #endif
    5080           0 :     contexts_not_empty();
    5081             : 
    5082           0 :     variant_t expr_result(pop_variant_data());
    5083           0 :     if(expr_result.getType() != atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET)
    5084             :     {
    5085           0 :         throw QDomXPathException_WrongType("the 'next_context_node' operation expected the input to be a node-set");
    5086             :     }
    5087             : 
    5088           0 :     context_vector_t::reference context(f_functions.back().f_contexts.back());
    5089             : 
    5090           0 :     QDomXPath::node_vector_t r(expr_result.getNodeSetValue());
    5091           0 :     QDomXPath::node_vector_t& context_result(context.f_result);
    5092           0 :     const int imax(r.size());
    5093           0 :     for(int i(0); i < imax; ++i)
    5094             :     {
    5095           0 :         context_result.push_back(r[i]);
    5096             :     }
    5097             : 
    5098             :     // if +1 to position is too large, just return false
    5099           0 :     const bool has_another_position(context.f_position + 1 < context.f_nodes.size());
    5100           0 :     if(has_another_position)
    5101             :     {
    5102           0 :         ++context.f_position;
    5103             :     }
    5104             : 
    5105           0 :     variant_t value;
    5106           0 :     value.atomic_value_t::setValue(has_another_position);
    5107           0 :     f_functions.back().f_stack.push_back(value);
    5108           0 : }
    5109             : 
    5110             : 
    5111           0 : void inst_pop_context()
    5112             : {
    5113             : #if QDOM_XPATH_VERIFICATION
    5114             :     // verify instruction location
    5115           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_POP_CONTEXT)
    5116             :     {
    5117           0 :         throw QDomXPathException_InternalError("INST_POP_CONTEXT not at the right location in the table of instructions");
    5118             :     }
    5119             : #endif
    5120           0 :     contexts_not_empty();
    5121           0 :     f_functions.back().f_contexts.pop_back();
    5122           0 : }
    5123             : 
    5124             : 
    5125           0 : void inst_get_context_node()
    5126             : {
    5127             : #if QDOM_XPATH_VERIFICATION
    5128             :     // verify instruction location
    5129           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_GET_CONTEXT_NODE)
    5130             :     {
    5131           0 :         throw QDomXPathException_InternalError("INST_GET_CONTEXT_NODE not at the right location in the table of instructions");
    5132             :     }
    5133             : #endif
    5134           0 :     contexts_not_empty();
    5135           0 :     const context_t context(f_functions.back().f_contexts.back());
    5136           0 :     QDomXPath::node_vector_t node_set;
    5137           0 :     if(context.f_position != -1)
    5138             :     {
    5139           0 :         node_set.push_back(context.f_nodes[context.f_position]);
    5140             :     }
    5141           0 :     variant_t result;
    5142           0 :     result.setValue(node_set);
    5143           0 :     f_functions.back().f_stack.push_back(result);
    5144           0 : }
    5145             : 
    5146             : 
    5147             : /** \brief Compute an axis.
    5148             :  *
    5149             :  * This function computes a list of nodes as specified by the axis
    5150             :  * parameters.
    5151             :  *
    5152             :  * In some cases this can result in a very large number of nodes getting
    5153             :  * pushed around!
    5154             :  */
    5155           0 : void inst_axis()
    5156             : {
    5157             : #if QDOM_XPATH_VERIFICATION
    5158             :     // verify instruction location
    5159           0 :     if(f_program[f_functions.back().f_pc - 1] != INST_AXIS)
    5160             :     {
    5161           0 :         throw QDomXPathException_InternalError("INST_AXIS not at the right location in the table of instructions");
    5162             :     }
    5163             : #endif
    5164             :     // the first parameter is the axis (enum axis_t)
    5165           0 :     variant_t axis_variant(pop_variant_data());
    5166           0 :     axis_t axis(static_cast<axis_t>(axis_variant.getIntegerValue()));
    5167             : 
    5168             :     // the next parameter is the prefix or the node type parameter
    5169             :     // (in case of a processing-instruction node)
    5170           0 :     variant_t prefix_or_processing_language(pop_variant_data());
    5171           0 :     QString prefix;
    5172           0 :     QString processing_language;
    5173             : 
    5174             :     // the next parameter is the local_part (i.e. path entry)
    5175             :     // or the node type enumeration (enum node_type_t)
    5176           0 :     variant_t local_part_or_node_type(pop_variant_data());
    5177           0 :     QString local_part;
    5178           0 :     node_type_t node_type(node_type_t::NODE_TYPE_ELEMENT);
    5179             : 
    5180             :     // the last parameter is the context node which we cannot pop because
    5181             :     // it is required to run through all the nodes, we only make use of the
    5182             :     // context node which is the one we're interested in
    5183           0 :     variant_t context_node_variant(pop_variant_data());
    5184           0 :     if(context_node_variant.getType() != atomic_value_t::type_t::ATOMIC_TYPE_NODE_SET)
    5185             :     {
    5186           0 :         throw QDomXPathException_WrongType("the 4th axis parameters must be a node-set");
    5187             :     }
    5188             :     //stack_not_empty(atomic_value_t::type_t::ATOMIC_TYPE_CONTEXT);
    5189             :     //context_t& context(f_functions.back().f_stack.back().getContextValue());
    5190             :     //variant_t context_variant(pop_variant_data());
    5191             :     //context_t& context(context_variant.getContextValue());
    5192             : 
    5193           0 :     if(local_part_or_node_type.getType() == atomic_value_t::type_t::ATOMIC_TYPE_INTEGER)
    5194             :     {
    5195             :         // we have a node type, thus if not empty the
    5196             :         // prefix_or_processing_language variable is the
    5197             :         // language name to match
    5198           0 :         if(axis == axis_t::AXIS_ATTRIBUTE || axis == axis_t::AXIS_NAMESPACE)
    5199             :         {
    5200             :             // Note: XPath 2.0 has an 'attribute' NodeType (KindTest) which
    5201             :             //       means attribute axis would be fine here
    5202           0 :             throw QDomXPathException_WrongType("attribute and namespace axis are not compatible with a node type");
    5203             :         }
    5204           0 :         node_type = static_cast<node_type_t>(local_part_or_node_type.getIntegerValue());
    5205           0 :         processing_language = prefix_or_processing_language.getStringValue();
    5206             :     }
    5207             :     else
    5208             :     {
    5209             :         // we got a prefix + local_name
    5210           0 :         prefix = prefix_or_processing_language.getStringValue();
    5211           0 :         local_part = local_part_or_node_type.getStringValue();
    5212           0 :         if(local_part == "*")
    5213             :         {
    5214           0 :             local_part = "";
    5215             :         }
    5216             : 
    5217           0 :         if(axis == axis_t::AXIS_ATTRIBUTE)
    5218             :         {
    5219             :             // This is an XPath 2.0 feature
    5220           0 :             node_type = node_type_t::NODE_TYPE_ATTRIBUTE;
    5221             :         }
    5222             :     }
    5223           0 :     const bool any_prefix(prefix == "*");
    5224             : 
    5225             :     // node_type_t::NODE_TYPE_COMMENT
    5226             :     // node_type_t::NODE_TYPE_NODE
    5227             :     // node_type_t::NODE_TYPE_PROCESSING_INSTRUCTION
    5228             :     // node_type_t::NODE_TYPE_TEXT
    5229           0 :     QDomNode::NodeType dom_node_type( QDomNode::ElementNode );
    5230           0 :     switch(node_type)
    5231             :     {
    5232           0 :     case node_type_t::NODE_TYPE_COMMENT:
    5233           0 :         dom_node_type = QDomNode::CommentNode;
    5234           0 :         break;
    5235             : 
    5236           0 :     case node_type_t::NODE_TYPE_NODE: // any node? (BaseNode)
    5237             :     case node_type_t::NODE_TYPE_ELEMENT:
    5238           0 :         dom_node_type = QDomNode::ElementNode;
    5239           0 :         break;
    5240             : 
    5241           0 :     case node_type_t::NODE_TYPE_PROCESSING_INSTRUCTION:
    5242           0 :         dom_node_type = QDomNode::ProcessingInstructionNode;
    5243           0 :         break;
    5244             : 
    5245           0 :     case node_type_t::NODE_TYPE_TEXT:
    5246           0 :         dom_node_type = QDomNode::TextNode;
    5247             :         // should include QDomNode::CDATASectionNode
    5248           0 :         break;
    5249             : 
    5250           0 :     case node_type_t::NODE_TYPE_DOCUMENT_NODE:
    5251           0 :         dom_node_type = QDomNode::DocumentNode;
    5252           0 :         break;
    5253             : 
    5254           0 :     case node_type_t::NODE_TYPE_SCHEMA_ELEMENT:
    5255             :         //dom_node_type = QDomNode::??;
    5256           0 :         throw QDomXPathException_NotImplemented("the schema_element node type is not yet implemented");
    5257             :         break;
    5258             : 
    5259           0 :     case node_type_t::NODE_TYPE_ATTRIBUTE:
    5260           0 :         dom_node_type = QDomNode::AttributeNode;
    5261           0 :         break;
    5262             : 
    5263           0 :     case node_type_t::NODE_TYPE_SCHEMA_ATTRIBUTE:
    5264             :         //dom_node_type = QDomNode::??;
    5265           0 :         throw QDomXPathException_NotImplemented("the schema_attribute node type is not yet implemented");
    5266             :         break;
    5267             : 
    5268             :     }
    5269             : 
    5270           0 :     QDomXPath::node_vector_t result;
    5271           0 :     QDomNode context_node;
    5272           0 :     if(context_node_variant.getNodeSetValue().size() == 1) // TBD -- can it even be more than one?
    5273             :     {
    5274           0 :         context_node = context_node_variant.getNodeSetValue()[0];
    5275             :     }
    5276             : 
    5277             :     // axis only applies on element nodes, right?
    5278           0 :     if(context_node.isElement()
    5279           0 :     || context_node.isDocument())
    5280             :     {
    5281           0 :         switch(axis)
    5282             :         {
    5283           0 :         case axis_t::AXIS_SELF:
    5284           0 :             switch(node_type)
    5285             :             {
    5286           0 :             case node_type_t::NODE_TYPE_NODE:
    5287             :             case node_type_t::NODE_TYPE_ELEMENT:
    5288             :                 // as far as I know the type node is considered to be
    5289             :                 // the same as elements (at least in XPath 1.0)
    5290             :                 // the local_part & prefix must match for us to keep the node
    5291           0 :                 if(!context_node.isNull()
    5292           0 :                 && (local_part.isEmpty() || local_part == context_node.toElement().tagName())
    5293           0 :                 && (any_prefix || prefix == context_node.prefix()))
    5294             :                 {
    5295           0 :                     result.push_back(context_node);
    5296             :                 }
    5297           0 :                 break;
    5298             : 
    5299           0 :             default:
    5300           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5301             : 
    5302             :             }
    5303           0 :             break;
    5304             : 
    5305           0 :         case axis_t::AXIS_PARENT:
    5306           0 :             switch(node_type)
    5307             :             {
    5308           0 :             case node_type_t::NODE_TYPE_NODE:
    5309             :             case node_type_t::NODE_TYPE_ELEMENT:
    5310             :                 {
    5311             :                     // as far as I know the type node is considered to be
    5312             :                     // the same as elements (at least in XPath 1.0)
    5313           0 :                     QDomNode node(context_node.parentNode());
    5314             :                     // the local_part & prefix must match for us to keep the node
    5315           0 :                     if(!node.isNull()
    5316           0 :                     && (local_part.isEmpty() || local_part == node.toElement().tagName())
    5317           0 :                     && (any_prefix || prefix == node.prefix()))
    5318             :                     {
    5319           0 :                         result.push_back(node);
    5320           0 :                     }
    5321             :                 }
    5322           0 :                 break;
    5323             : 
    5324           0 :             default:
    5325           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5326             : 
    5327             :             }
    5328           0 :             break;
    5329             : 
    5330             :         case axis_t::AXIS_ATTRIBUTE:
    5331           0 : axis_attribute:
    5332           0 :             if(local_part.isEmpty())
    5333             :             {
    5334           0 :                 QDomNamedNodeMap attributes(context_node.attributes());
    5335           0 :                 const int imax(attributes.size());
    5336           0 :                 for(int i(0); i < imax; ++i)
    5337             :                 {
    5338           0 :                     QDomNode attr(attributes.item(i));
    5339           0 :                     if(any_prefix || prefix == attr.prefix())
    5340             :                     {
    5341           0 :                         result.push_back(attr);
    5342             :                     }
    5343             :                 }
    5344             :             }
    5345             :             else
    5346             :             {
    5347             :                 // no need to go through the whole list slowly if
    5348             :                 // we can just query the map at once
    5349           0 :                 QDomNode attr(context_node.attributes().namedItem(local_part));
    5350           0 :                 if(!attr.isNull()
    5351           0 :                 && (any_prefix || prefix == attr.prefix()))
    5352             :                 {
    5353           0 :                     result.push_back(attr);
    5354             :                 }
    5355             :             }
    5356           0 :             break;
    5357             : 
    5358           0 :         case axis_t::AXIS_ANCESTOR:
    5359             :         case axis_t::AXIS_ANCESTOR_OR_SELF:
    5360           0 :             switch(node_type)
    5361             :             {
    5362           0 :             case node_type_t::NODE_TYPE_NODE:
    5363             :             case node_type_t::NODE_TYPE_ELEMENT:
    5364             :                 {
    5365             :                     // as far as I know the type node is considered to be
    5366             :                     // the same as elements (at least in XPath 1.0)
    5367           0 :                     QDomNode node(context_node);
    5368           0 :                     if(axis == axis_t::AXIS_ANCESTOR)
    5369             :                     {
    5370           0 :                         node = node.parentNode();
    5371             :                     }
    5372           0 :                     while(!node.isNull())
    5373             :                     {
    5374             :                         // the local_part & prefix must match for us to keep the node
    5375           0 :                         if((local_part.isEmpty() || local_part == node.toElement().tagName())
    5376           0 :                         && (any_prefix || prefix == node.prefix()))
    5377             :                         {
    5378           0 :                             result.push_back(node);
    5379             :                         }
    5380           0 :                         node = node.parentNode();
    5381           0 :                     }
    5382             :                 }
    5383           0 :                 break;
    5384             : 
    5385           0 :             default:
    5386           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5387             : 
    5388             :             }
    5389           0 :             break;
    5390             : 
    5391           0 :         case axis_t::AXIS_CHILD:
    5392           0 :             switch(node_type)
    5393             :             {
    5394           0 :             case node_type_t::NODE_TYPE_NODE:
    5395             :             case node_type_t::NODE_TYPE_ELEMENT:
    5396             :                 {
    5397             :                     // as far as I know the type node is considered to be
    5398             :                     // the same as elements (at least in XPath 1.0)
    5399             :                     //
    5400             :                     // TBD: here we may want to add support for XML files
    5401             :                     //      that were loaded without setting the
    5402             :                     //      namespaceProcessing parameter set to true
    5403             :                     //      (i.e. thus tag names are "blah:foo")
    5404           0 :                     QDomNode node(context_node.firstChildElement(local_part));
    5405           0 :                     while(!node.isNull())
    5406             :                     {
    5407             :                         // the prefix must also match
    5408           0 :                         if(any_prefix || prefix == node.prefix())
    5409             :                         {
    5410           0 :                             result.push_back(node);
    5411             :                         }
    5412           0 :                         node = node.nextSiblingElement(local_part);
    5413           0 :                     }
    5414             :                 }
    5415           0 :                 break;
    5416             : 
    5417           0 :             case node_type_t::NODE_TYPE_ATTRIBUTE:
    5418           0 :                 goto axis_attribute;
    5419             : 
    5420           0 :             case node_type_t::NODE_TYPE_COMMENT:
    5421             :             case node_type_t::NODE_TYPE_TEXT:
    5422             :                 {
    5423           0 :                     QDomNode node(context_node.firstChildElement(local_part));
    5424           0 :                     while(!node.isNull())
    5425             :                     {
    5426             :                         // the prefix must also match
    5427           0 :                         if(dom_node_type == node.nodeType()
    5428           0 :                         && (any_prefix || prefix == node.prefix()))
    5429             :                         {
    5430           0 :                             result.push_back(node);
    5431             :                         }
    5432           0 :                         node = node.nextSiblingElement(local_part);
    5433           0 :                     }
    5434             :                 }
    5435           0 :                 break;
    5436             : 
    5437           0 :             case node_type_t::NODE_TYPE_PROCESSING_INSTRUCTION:
    5438             :                 {
    5439           0 :                     QDomNode node(context_node.firstChildElement(local_part));
    5440           0 :                     while(!node.isNull())
    5441             :                     {
    5442             :                         // the prefix must also match
    5443           0 :                         if(QDomNode::ProcessingInstructionNode == node.nodeType()
    5444           0 :                         && node.isProcessingInstruction()
    5445           0 :                         && prefix == node.prefix())
    5446             :                         {
    5447           0 :                             if(!processing_language.isEmpty())
    5448             :                             {
    5449             :                                 // further test the processing language
    5450           0 :                                 QDomProcessingInstruction pi(node.toProcessingInstruction());
    5451           0 :                                 if(pi.target() == processing_language)
    5452             :                                 {
    5453           0 :                                     result.push_back(node);
    5454             :                                 }
    5455             :                             }
    5456             :                             else
    5457             :                             {
    5458           0 :                                 result.push_back(node);
    5459             :                             }
    5460             :                         }
    5461           0 :                         node = node.nextSiblingElement(local_part);
    5462           0 :                     }
    5463             :                 }
    5464           0 :                 break;
    5465             : 
    5466           0 :             default:
    5467           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5468             : 
    5469             :             }
    5470           0 :             break;
    5471             : 
    5472           0 :         case axis_t::AXIS_DESCENDANT:
    5473             :         case axis_t::AXIS_DESCENDANT_OR_SELF:
    5474           0 :             switch(node_type)
    5475             :             {
    5476           0 :             case node_type_t::NODE_TYPE_NODE:
    5477             :             case node_type_t::NODE_TYPE_ELEMENT:
    5478             :                 {
    5479             :                     // as far as I know the type node is considered to be
    5480             :                     // the same as elements (at least in XPath 1.0)
    5481           0 :                     QDomNode node(context_node);
    5482           0 :                     if(axis == axis_t::AXIS_DESCENDANT_OR_SELF
    5483           0 :                     && (local_part.isEmpty() || local_part == context_node.toElement().tagName())
    5484           0 :                     && (any_prefix || prefix == context_node.prefix()))
    5485             :                     {
    5486           0 :                         result.push_back(context_node);
    5487             :                     }
    5488           0 :                     while(!node.isNull())
    5489             :                     {
    5490           0 :                         QDomNode next(node.firstChild());
    5491           0 :                         if(next.isNull())
    5492             :                         {
    5493           0 :                             next = node;
    5494           0 :                             while(!next.isNull()) // this should never happend since we should bump in context_node first
    5495             :                             {
    5496           0 :                                 if(next == context_node)
    5497             :                                 {
    5498             :                                     // break 2;
    5499           0 :                                     goto axis_descendant_done;
    5500             :                                 }
    5501           0 :                                 QDomNode parent(next.parentNode());
    5502           0 :                                 next = next.nextSibling();
    5503           0 :                                 if(!next.isNull())
    5504             :                                 {
    5505           0 :                                     break;
    5506             :                                 }
    5507           0 :                                 next = parent;
    5508             :                             }
    5509             :                         }
    5510             :                         // the local_part & prefix must match for us to keep the node
    5511           0 :                         node = next;
    5512           0 :                         if((local_part.isEmpty() || local_part == node.toElement().tagName())
    5513           0 :                         && (any_prefix || prefix == node.prefix()))
    5514             :                         {
    5515             :                             // push so nodes stay in document order
    5516           0 :                             result.push_back(node);
    5517             :                         }
    5518             :                     }
    5519           0 : axis_descendant_done:;
    5520             :                 }
    5521           0 :                 break;
    5522             : 
    5523           0 :             default:
    5524           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5525             : 
    5526             :             }
    5527           0 :             break;
    5528             : 
    5529           0 :         case axis_t::AXIS_NAMESPACE:
    5530             :             /*
    5531             :              * I found the following documentation about namespace nodes on
    5532             :              * an Oracle website:
    5533             :              *
    5534             :              * http://docs.oracle.com/cd/B19306_01/appdev.102/b14259/appcxpa.htm
    5535             :              *
    5536             :              * It clearly explains what the so called "Namespace Nodes" are
    5537             :              * and at this time we simply do not support them at all for
    5538             :              * several reasons:
    5539             :              *
    5540             :              * \li We do not need them.
    5541             :              * \li XPath 2.0 does not support them (it is clearly marked
    5542             :              *     as deprecated).
    5543             :              * \li Namespace Nodes are not actual nodes in the DOM. We'd
    5544             :              *     have to simulate those special nodes and that's a lot
    5545             :              *     of special cases for something nearly no one uses.
    5546             :              *
    5547             :              * Oracle documentation:
    5548             :              *
    5549             :              * Namespace Nodes
    5550             :              *
    5551             :              * Each element has an associated set of namespace nodes, one for
    5552             :              * each distinct namespace prefix that is in scope for the element
    5553             :              * (including the xml prefix, which is implicitly declared by the
    5554             :              * XML Namespaces Recommendation) and one for the default namespace
    5555             :              * if one is in scope for the element. The element is the parent of
    5556             :              * each of these namespace nodes; however, a namespace node is not
    5557             :              * a child of its parent element.
    5558             :              *
    5559             :              * Elements never share namespace nodes: if one element node is not
    5560             :              * the same node as another element node, then none of the
    5561             :              * namespace nodes of the one element node will be the same node as
    5562             :              * the namespace nodes of another element node. This means that an
    5563             :              * element will have a namespace node:
    5564             :              *
    5565             :              * For every attribute on the element whose name starts with
    5566             :              * xmlns:;
    5567             :              *
    5568             :              * For every attribute on an ancestor element whose name starts
    5569             :              * xmlns: unless the element itself or a nearer ancestor
    5570             :              * re-declares the prefix;
    5571             :              *
    5572             :              * For an xmlns attribute, if the element or some ancestor has an
    5573             :              * xmlns attribute, and the value of the xmlns attribute for the
    5574             :              * nearest such element is nonempty
    5575             :              *
    5576             :              * \note
    5577             :              * An attribute xmlns="" undeclares the default namespace.
    5578             :              *
    5579             :              * A namespace node has an expanded-name: the local part is the
    5580             :              * namespace prefix (this is empty if the namespace node is for the
    5581             :              * default namespace); the namespace URI is always NULL.
    5582             :              *
    5583             :              * The string-value of a namespace node is the namespace URI that
    5584             :              * is being bound to the namespace prefix; if it is relative, then
    5585             :              * it must be resolved just like a namespace URI in an
    5586             :              * expanded-name.
    5587             :              */
    5588           0 :             throw QDomXPathException_NotImplemented("the namespace axis is not implemented");
    5589             : 
    5590           0 :         case axis_t::AXIS_FOLLOWING:
    5591             :         case axis_t::AXIS_FOLLOWING_SIBLING:
    5592           0 :             switch(node_type)
    5593             :             {
    5594           0 :             case node_type_t::NODE_TYPE_NODE:
    5595             :             case node_type_t::NODE_TYPE_ELEMENT:
    5596             :                 {
    5597             :                     // as far as I know the type node is considered to be
    5598             :                     // the same as elements (at least in XPath 1.0)
    5599           0 :                     QDomNode node(context_node.nextSibling());
    5600           0 :                     while(!node.isNull())
    5601             :                     {
    5602             :                         // the local_part & prefix must match for us to keep the node
    5603           0 :                         if((local_part.isEmpty() || local_part == node.toElement().tagName())
    5604           0 :                         && (any_prefix || prefix == node.prefix()))
    5605             :                         {
    5606             :                             // push so nodes stay in document order
    5607           0 :                             result.push_back(node);
    5608             :                         }
    5609           0 :                         node = node.nextSibling();
    5610             :                     }
    5611           0 :                     if(axis == axis_t::AXIS_FOLLOWING)
    5612             :                     {
    5613           0 :                         QDomNode next(context_node.parentNode());
    5614           0 :                         while(!next.isNull())
    5615             :                         {
    5616           0 :                             QDomNode parent(next.parentNode());
    5617           0 :                             next = next.nextSibling();
    5618           0 :                             if(!next.isNull())
    5619             :                             {
    5620           0 :                                 break;
    5621             :                             }
    5622           0 :                             next = parent;
    5623             :                         }
    5624           0 :                         while(!next.isNull())
    5625             :                         {
    5626             :                             // the local_part & prefix must match for us to keep the node
    5627           0 :                             node = next;
    5628           0 :                             if((local_part.isEmpty() || local_part == node.toElement().tagName())
    5629           0 :                             && (any_prefix || prefix == node.prefix()))
    5630             :                             {
    5631             :                                 // push so nodes stay in document order
    5632           0 :                                 result.push_back(node);
    5633             :                             }
    5634           0 :                             next = node.firstChild();
    5635           0 :                             if(next.isNull())
    5636             :                             {
    5637           0 :                                 next = node;
    5638           0 :                                 while(!next.isNull())
    5639             :                                 {
    5640           0 :                                     QDomNode parent(next.parentNode());
    5641           0 :                                     next = next.nextSibling();
    5642           0 :                                     if(!next.isNull())
    5643             :                                     {
    5644           0 :                                         break;
    5645             :                                     }
    5646           0 :                                     next = parent;
    5647             :                                 }
    5648             :                             }
    5649             :                         }
    5650           0 :                     }
    5651             :                 }
    5652           0 :                 break;
    5653             : 
    5654           0 :             default:
    5655           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5656             : 
    5657             :             }
    5658           0 :             break;
    5659             : 
    5660           0 :         case axis_t::AXIS_PRECEDING:
    5661             :         case axis_t::AXIS_PRECEDING_SIBLING:
    5662             :             // WARNING: 'preceding' never include the ancestors
    5663           0 :             switch(node_type)
    5664             :             {
    5665           0 :             case node_type_t::NODE_TYPE_NODE:
    5666             :             case node_type_t::NODE_TYPE_ELEMENT:
    5667             :                 {
    5668             :                     // as far as I know the type node is considered to be
    5669             :                     // the same as elements (at least in XPath 1.0)
    5670           0 :                     QDomNode node(context_node.previousSibling());
    5671           0 :                     while(!node.isNull())
    5672             :                     {
    5673             :                         // the local_part & prefix must match for us to keep the node
    5674           0 :                         if((local_part.isEmpty() || local_part == node.toElement().tagName())
    5675           0 :                         && (any_prefix || prefix == node.prefix()))
    5676             :                         {
    5677           0 :                             result.push_back(node);
    5678             :                         }
    5679           0 :                         node = node.previousSibling();
    5680             :                     }
    5681           0 :                     if(axis == axis_t::AXIS_PRECEDING)
    5682             :                     {
    5683           0 :                         QDomNode previous(context_node.parentNode());
    5684           0 :                         while(!previous.isNull())
    5685             :                         {
    5686           0 :                             QDomNode parent(previous.parentNode());
    5687           0 :                             previous = previous.previousSibling();
    5688           0 :                             if(!previous.isNull())
    5689             :                             {
    5690           0 :                                 break;
    5691             :                             }
    5692           0 :                             previous = parent;
    5693             :                         }
    5694           0 :                         while(!previous.isNull())
    5695             :                         {
    5696             :                             // the local_part & prefix must match for us to keep the node
    5697           0 :                             node = previous;
    5698           0 :                             if((local_part.isEmpty() || local_part == node.toElement().tagName())
    5699           0 :                             && (any_prefix || prefix == node.prefix()))
    5700             :                             {
    5701           0 :                                 result.push_back(node);
    5702             :                             }
    5703           0 :                             previous = node.lastChild();
    5704           0 :                             if(previous.isNull())
    5705             :                             {
    5706           0 :                                 do
    5707             :                                 {
    5708           0 :                                     QDomNode parent(node.parentNode());
    5709           0 :                                     previous = node.previousSibling();
    5710           0 :                                     if(!previous.isNull())
    5711             :                                     {
    5712           0 :                                         break;
    5713             :                                     }
    5714           0 :                                     node = parent;
    5715             :                                 }
    5716           0 :                                 while(!previous.isNull());
    5717             :                             }
    5718             :                         }
    5719           0 :                     }
    5720             :                 }
    5721           0 :                 break;
    5722             : 
    5723           0 :             default:
    5724           0 :                 throw QDomXPathException_NotImplemented(QString("this axis (%1) does not support this node type (%2)").arg(static_cast<int>(axis)).arg(static_cast<int>(node_type)));
    5725             : 
    5726             :             }
    5727           0 :             break;
    5728             : 
    5729             :         }
    5730             :     }
    5731             : 
    5732           0 :     variant_t node_set;
    5733           0 :     node_set.setValue(result);
    5734           0 :     f_functions.back().f_stack.push_back(node_set);
    5735           0 : }
    5736             : 
    5737             : 
    5738             : 
    5739             : 
    5740             : 
    5741             : 
    5742             : 
    5743             : /** \brief Get the next character.
    5744             :  *
    5745             :  * This function returns the next character found in the input string.
    5746             :  * If the character is invalid, the function throws an exception.
    5747             :  *
    5748             :  * Note that the function returns characters encoded in UTF-16, even
    5749             :  * though XML expects UCS-4 characters. The main reason is because the
    5750             :  * QString implementation returns those characters in this way. This
    5751             :  * works because none of the characters with code values larger than
    5752             :  * 0xFFFF are tested within this parser. All of those are viewed as
    5753             :  * standard 'Char' and thus they can as well be defined as 0xD800 to
    5754             :  * 0xDFFF byte codes.
    5755             :  *
    5756             :  * \exception QDomXPathException_InvalidCharacter
    5757             :  * This exception is raised in the even an input character is not a valid
    5758             :  * XML character (i.e. Ctrl-A is not acceptable in the input.)
    5759             :  *
    5760             :  * \return The next character in the form of an encoded UTF-16 character.
    5761             :  */
    5762           0 : char_t getc()
    5763             : {
    5764           0 :     char_t c(f_in->unicode());
    5765           0 :     if(c == '\0')
    5766             :     {
    5767           0 :         return END_OF_PATH;
    5768             :     }
    5769             :     // Char ::= #x9
    5770             :     //        | #xA
    5771             :     //        | #xD
    5772             :     //        | [#x20-#xD7FF]
    5773             :     //        | [#xE000-#xFFFD]
    5774             :     //        | [#x10000-#x10FFFF]
    5775             :     // The Qt QChar is a UTF-16 character which means that
    5776             :     // characters larger then 0xFFFF are defined with codes
    5777             :     // between 0xD800 and 0xDFFF. These are therefore included
    5778             :     // although we could check that the characters are correct
    5779             :     // we do not because we do not have to test for specific
    5780             :     // characters with codes that large.)
    5781           0 :     if(c != 0x09
    5782           0 :     && c != 0x0A
    5783           0 :     && c != 0x0D
    5784           0 :     && (c < 0x20 || c > 0xFFFD))
    5785             :     {
    5786           0 :         throw QDomXPathException_InvalidCharacter(QString("invalid XML character 0x%1").arg(static_cast<int>(c), 4, 16, QChar('0')));
    5787             :     }
    5788           0 :     ++f_in;
    5789           0 :     return c;
    5790             : }
    5791             : 
    5792             : /** \brief Restore the input character pointer position.
    5793             :  *
    5794             :  * This function can be called to restore the character pointer position
    5795             :  * to a previous position. It can be called as many times as the getc()
    5796             :  * function was called. However, note that you cannot specify which
    5797             :  * character is being ungotten. It will always be the character that
    5798             :  * you got at that time with getc().
    5799             :  *
    5800             :  * Note that the function takes a character as input, if that character is
    5801             :  * END_OF_PATH, then ungetc() does nothing. This can be a problem if multiple
    5802             :  * ungetc() need to be used. In that case, just use a character such as ' '.
    5803             :  *
    5804             :  * \exception QDomXPathException_TooManyUnget
    5805             :  * As a protection, the function checks that the unget() function is called
    5806             :  * more times than the get() function was called. If so, we have a bug.
    5807             :  *
    5808             :  * \param[in] c  The character to be ungotten.
    5809             :  */
    5810           0 : void ungetc(char_t c)
    5811             : {
    5812           0 :     if(c == END_OF_PATH)
    5813             :     {
    5814           0 :         return;
    5815             :     }
    5816           0 :     if(f_in <= f_start)
    5817             :     {
    5818           0 :         throw QDomXPathException_TooManyUnget("ungetc() called too many times, the algorithm is spurious");
    5819             :     }
    5820           0 :     --f_in;
    5821             : }
    5822             : 
    5823             : /** \brief Get the next token.
    5824             :  *
    5825             :  * This function reads one XML XPath token from the input. This can be a
    5826             :  * single character ('(' or '@') or a whole complex token such as a string
    5827             :  * or a real number.
    5828             :  *
    5829             :  * The function returns true if the token was successfully read. The token
    5830             :  * is found in the f_last_token variable. If necessary, the token can be
    5831             :  * copied for further processing at a later time.
    5832             :  *
    5833             :  * \exception QDomXPathException_InvalidCharacter
    5834             :  * This exception is raised if an invalid combination of characters is found.
    5835             :  * For example, the exclamation mark ('!') character must be followed by
    5836             :  * an equal sign ('=') to be valid.
    5837             :  *
    5838             :  * \exception QDomXPathException_InvalidString
    5839             :  * This exception is raised whenever a string ends without a quote (i.e. we
    5840             :  * reached the end of the input buffer before the end of the string.)
    5841             :  *
    5842             :  * \return true if a token was read, false if no more tokens are available.
    5843             :  */
    5844           0 : bool get_token()
    5845             : {
    5846             :     // ExprToken ::= '(' | ')'
    5847             :     //             | '[' | ']'
    5848             :     //             | '.'
    5849             :     //             | '..'
    5850             :     //             | '@'
    5851             :     //             | ','
    5852             :     //             | '::'
    5853             :     //             | NameTest
    5854             :     //             | NodeType
    5855             :     //             | Operator
    5856             :     //             | FunctionName
    5857             :     //             | AxisName
    5858             :     //             | Literal
    5859             :     //             | Number
    5860             :     //             | VariableReference
    5861             :     //
    5862             :     // Number ::= Digits ('.' Digits?)?
    5863             :     //          | '.' Digits
    5864             :     //
    5865             :     // Digits ::= [0-9]+
    5866             :     //
    5867             :     // Operator ::= OperatorName
    5868             :     //            | MultiplyOperator
    5869             :     //            | '/'
    5870             :     //            | '//'
    5871             :     //            | '|'
    5872             :     //            | '+'
    5873             :     //            | '-'
    5874             :     //            | '='
    5875             :     //            | '!='
    5876             :     //            | '<'
    5877             :     //            | '<='
    5878             :     //            | '>'
    5879             :     //            | '>='
    5880             :     //
    5881             :     // MultiplyOperator ::= '*'
    5882             :     //
    5883             :     // Literal ::= '"' [^"]* '"'
    5884             :     //           | "'" [^']* "'"
    5885             :     //
    5886             :     // NameTest ::= '*'
    5887             :     //            | NCName ':' '*'
    5888             :     //            | QName
    5889             :     //
    5890             :     // NCName ::= Name - (Char* ':' Char*)
    5891             :     //
    5892             :     // NameStartChar ::= ':'
    5893             :     //                 | [A-Z]
    5894             :     //                 | '_'
    5895             :     //                 | [a-z]
    5896             :     //                 | [#xC0-#xD6]
    5897             :     //                 | [#xD8-#xF6]
    5898             :     //                 | [#xF8-#x2FF]
    5899             :     //                 | [#x370-#x37D]
    5900             :     //                 | [#x37F-#x1FFF]
    5901             :     //                 | [#x200C-#x200D]
    5902             :     //                 | [#x2070-#x218F]
    5903             :     //                 | [#x2C00-#x2FEF]
    5904             :     //                 | [#x3001-#xD7FF]
    5905             :     //                 | [#xF900-#xFDCF]
    5906             :     //                 | [#xFDF0-#xFFFD]
    5907             :     //                 | [#x10000-#xEFFFF]
    5908             :     //
    5909             :     // NameChar ::= NameStartChar
    5910             :     //            | '-'
    5911             :     //            | '.'
    5912             :     //            | [0-9]
    5913             :     //            | #xB7
    5914             :     //            | [#x0300-#x036F]
    5915             :     //            | [#x203F-#x2040]
    5916             :     //
    5917             :     // Name ::= NameStartChar (NameChar)*
    5918             :     //
    5919             :     // OperatorName ::= 'and'
    5920             :     //                | 'or'
    5921             :     //                | 'mod'
    5922             :     //                | 'div'
    5923             :     //
    5924             :     // NodeType ::= 'comment'
    5925             :     //            | 'text'
    5926             :     //            | 'processing-instruction'
    5927             :     //            | 'node'
    5928             :     //
    5929             :     // FunctionName ::= QName - NodeType
    5930             :     //
    5931             :     // AxisName ::= 'ancestor'
    5932             :     //            | 'ancestor-or-self'
    5933             :     //            | 'attribute'
    5934             :     //            | 'child'
    5935             :     //            | 'descendant'
    5936             :     //            | 'descendant-or-self'
    5937             :     //            | 'following'
    5938             :     //            | 'following-sibling'
    5939             :     //            | 'namespace'
    5940             :     //            | 'parent'
    5941             :     //            | 'preceding'
    5942             :     //            | 'preceding-sibling'
    5943             :     //            | 'self'
    5944             :     //
    5945             :     // VariableReference ::= '$' QName
    5946             :     //
    5947             :     // QName ::= PrefixedName
    5948             :     //         | UnprefixedName
    5949             :     //
    5950             :     // PrefixedName ::= Prefix ':' LocalPart
    5951             :     //
    5952             :     // UnprefixedName ::= LocalPart
    5953             :     //
    5954             :     // Prefix ::= NCName
    5955             :     //
    5956             :     // LocalPart ::= NCName
    5957             :     //
    5958             : 
    5959             : 
    5960             :     // if we got an ungotten token, return it
    5961           0 :     if(f_unget_token)
    5962             :     {
    5963           0 :         f_last_token = f_unget_token;
    5964           0 :         f_unget_token.reset();
    5965           0 :         return f_last_token;
    5966             :     }
    5967             :     else
    5968             :     {
    5969           0 :         f_last_token.f_string = "";
    5970           0 :         char_t c(getc());
    5971             :         // ignore spaces between tokens
    5972           0 :         while(c == 0x20 || c == 0x09 || c == 0x0D || c == 0x0A)
    5973             :         {
    5974           0 :             c = getc();
    5975             :         }
    5976           0 :         if(c == END_OF_PATH)
    5977             :         {
    5978           0 :             f_last_token.reset();
    5979           0 :             return f_last_token;
    5980             :         }
    5981           0 :         f_last_token.f_string += QChar(c);
    5982           0 :         switch(c)
    5983             :         {
    5984           0 :         case '(':
    5985           0 :             f_last_token.f_token = token_t::tok_t::TOK_OPEN_PARENTHESIS;
    5986           0 :             break;
    5987             : 
    5988           0 :         case ')':
    5989           0 :             f_last_token.f_token = token_t::tok_t::TOK_CLOSE_PARENTHESIS;
    5990           0 :             break;
    5991             : 
    5992           0 :         case '[':
    5993           0 :             f_last_token.f_token = token_t::tok_t::TOK_OPEN_SQUARE_BRACKET;
    5994           0 :             break;
    5995             : 
    5996           0 :         case ']':
    5997           0 :             f_last_token.f_token = token_t::tok_t::TOK_CLOSE_SQUARE_BRACKET;
    5998           0 :             break;
    5999             : 
    6000           0 :         case '@':
    6001           0 :             f_last_token.f_token = token_t::tok_t::TOK_AT;
    6002           0 :             break;
    6003             : 
    6004           0 :         case ',':
    6005           0 :             f_last_token.f_token = token_t::tok_t::TOK_COMMA;
    6006           0 :             break;
    6007             : 
    6008           0 :         case ':':
    6009           0 :             c = getc();
    6010           0 :             if(c == ':')
    6011             :             {
    6012           0 :                 f_last_token.f_token = token_t::tok_t::TOK_DOUBLE_COLON;
    6013           0 :                 f_last_token.f_string += QChar(c);
    6014             :             }
    6015             :             else
    6016             :             {
    6017           0 :                 ungetc(c);
    6018           0 :                 f_last_token.f_token = token_t::tok_t::TOK_COLON;
    6019             :             }
    6020           0 :             break;
    6021             : 
    6022           0 :         case '/':
    6023           0 :             c = getc();
    6024           0 :             if(c == '/')
    6025             :             {
    6026           0 :                 f_last_token.f_token = token_t::tok_t::TOK_DOUBLE_SLASH;
    6027           0 :                 f_last_token.f_string += QChar(c);
    6028             :             }
    6029             :             else
    6030             :             {
    6031           0 :                 ungetc(c);
    6032           0 :                 f_last_token.f_token = token_t::tok_t::TOK_SLASH;
    6033             :             }
    6034           0 :             break;
    6035             : 
    6036           0 :         case '|':
    6037           0 :             f_last_token.f_token = token_t::tok_t::TOK_PIPE;
    6038           0 :             break;
    6039             : 
    6040           0 :         case '$':
    6041           0 :             f_last_token.f_token = token_t::tok_t::TOK_DOLLAR;
    6042           0 :             break;
    6043             : 
    6044           0 :         case '+':
    6045           0 :             f_last_token.f_token = token_t::tok_t::TOK_PLUS;
    6046           0 :             break;
    6047             : 
    6048           0 :         case '-':
    6049           0 :             f_last_token.f_token = token_t::tok_t::TOK_MINUS;
    6050           0 :             break;
    6051             : 
    6052           0 :         case '=':
    6053           0 :             f_last_token.f_token = token_t::tok_t::TOK_EQUAL;
    6054           0 :             break;
    6055             : 
    6056           0 :         case '!':
    6057           0 :             c = getc();
    6058           0 :             if(c == '=')
    6059             :             {
    6060           0 :                 f_last_token.f_token = token_t::tok_t::TOK_NOT_EQUAL;
    6061           0 :                 f_last_token.f_string += QChar(c);
    6062             :             }
    6063             :             else
    6064             :             {
    6065           0 :                 throw QDomXPathException_InvalidCharacter("found a stand alone '!' character which is not supported at that location");
    6066             :             }
    6067           0 :             break;
    6068             : 
    6069           0 :         case '<':
    6070           0 :             c = getc();
    6071           0 :             if(c == '=')
    6072             :             {
    6073           0 :                 f_last_token.f_token = token_t::tok_t::TOK_LESS_OR_EQUAL;
    6074           0 :                 f_last_token.f_string += QChar(c);
    6075             :             }
    6076             :             else
    6077             :             {
    6078           0 :                 ungetc(c);
    6079           0 :                 f_last_token.f_token = token_t::tok_t::TOK_LESS_THAN;
    6080             :             }
    6081           0 :             break;
    6082             : 
    6083           0 :         case '>':
    6084           0 :             c = getc();
    6085           0 :             if(c == '=')
    6086             :             {
    6087           0 :                 f_last_token.f_token = token_t::tok_t::TOK_GREATER_OR_EQUAL;
    6088           0 :                 f_last_token.f_string += QChar(c);
    6089             :             }
    6090             :             else
    6091             :             {
    6092           0 :                 ungetc(c);
    6093           0 :                 f_last_token.f_token = token_t::tok_t::TOK_GREATER_THAN;
    6094             :             }
    6095           0 :             break;
    6096             : 
    6097           0 :         case '*':
    6098             :             // '*' can represent a NameTest or the Multiply operator
    6099             :             // (this is context dependent)
    6100           0 :             f_last_token.f_token = token_t::tok_t::TOK_ASTERISK;
    6101           0 :             break;
    6102             : 
    6103           0 :         case '\'':
    6104             :         case '"':
    6105           0 :             f_last_token.f_token = token_t::tok_t::TOK_STRING;
    6106           0 :             f_last_token.f_string = ""; // remove the quote
    6107             :             {
    6108           0 :                 char_t quote(c);
    6109             :                 for(;;)
    6110             :                 {
    6111           0 :                     c = getc();
    6112           0 :                     if(c == END_OF_PATH)
    6113             :                     {
    6114           0 :                         throw QDomXPathException_InvalidString("a string that was not properly closed");
    6115             :                     }
    6116           0 :                     if(c == quote)
    6117             :                     {
    6118             :                         // in XPath 2.0 we can double quotes to insert
    6119             :                         // a quote in the string
    6120           0 :                         c = getc();
    6121           0 :                         if(c != quote)
    6122             :                         {
    6123           0 :                             ungetc(c);
    6124           0 :                             break;
    6125             :                         }
    6126             :                     }
    6127           0 :                     f_last_token.f_string += QChar(c);
    6128             :                 }
    6129             :             }
    6130           0 :             break;
    6131             : 
    6132           0 :         case '0':
    6133             :         case '1':
    6134             :         case '2':
    6135             :         case '3':
    6136             :         case '4':
    6137             :         case '5':
    6138             :         case '6':
    6139             :         case '7':
    6140             :         case '8':
    6141             :         case '9':
    6142           0 :             f_last_token.f_token = token_t::tok_t::TOK_INTEGER;
    6143           0 :             f_last_token.f_integer = c - '0';
    6144             :             for(;;)
    6145             :             {
    6146           0 :                 c = getc();
    6147           0 :                 if(c < '0' || c > '9')
    6148             :                 {
    6149             :                     break;
    6150             :                 }
    6151           0 :                 f_last_token.f_string += QChar(c);
    6152           0 :                 f_last_token.f_integer = f_last_token.f_integer * 10 + c - '0';
    6153             :             }
    6154           0 :             if(c != '.')
    6155             :             {
    6156           0 :                 ungetc(c);
    6157           0 :                 break;
    6158             :             }
    6159           0 :             f_last_token.f_string += QChar(c);
    6160           0 :             f_last_token.f_real = static_cast<double>(f_last_token.f_integer);
    6161             : #if __cplusplus >= 201700
    6162             :             [[fallthrough]];
    6163             : #endif
    6164           0 :         case '.':
    6165           0 :             c = getc();
    6166           0 :             if(f_last_token.f_string == ".")
    6167             :             {
    6168           0 :                 if(c == '.')
    6169             :                 {
    6170           0 :                     f_last_token.f_token = token_t::tok_t::TOK_DOUBLE_DOT;
    6171           0 :                     f_last_token.f_string += QChar(c);
    6172           0 :                     break;
    6173             :                 }
    6174           0 :                 else if(c < '0' || c > '9')
    6175             :                 {
    6176           0 :                     ungetc(c);
    6177           0 :                     f_last_token.f_token = token_t::tok_t::TOK_DOT;
    6178           0 :                     break;
    6179             :                 }
    6180           0 :                 f_last_token.f_string = "0.";
    6181             :             }
    6182           0 :             f_last_token.f_token = token_t::tok_t::TOK_REAL;
    6183             :             { // "protect" frac
    6184           0 :                 double frac(1.0);
    6185             :                 for(;;)
    6186             :                 {
    6187           0 :                     if(c < '0' || c > '9')
    6188             :                     {
    6189             :                         break;
    6190             :                     }
    6191           0 :                     f_last_token.f_string += QChar(c);
    6192           0 :                     frac /= 10.0;
    6193           0 :                     f_last_token.f_real += (c - '0') * frac;
    6194           0 :                     c = getc();
    6195           0 :                 }
    6196             :             }
    6197           0 :             ungetc(c);
    6198           0 :             if(f_last_token.f_string.right(1) == ".")
    6199             :             {
    6200           0 :                 f_last_token.f_string += '0';
    6201             :             }
    6202             :             // we prepend and append zeroes to the f_string for clarity
    6203             :             // yet, the function really returns f_last_token.f_real
    6204             :             // the f_last_token.f_integer is the floor()
    6205           0 :             break;
    6206             : 
    6207           0 :         default:
    6208           0 :             if((c >= 'a' && c <= 'z')
    6209           0 :             || (c >= 'A' && c <= 'Z')
    6210           0 :             || (c >= 0x00C0 && c <= 0x00D6)
    6211           0 :             || (c >= 0x00D8 && c <= 0x00F6)
    6212           0 :             || (c >= 0x00F8 && c <= 0x02FF)
    6213           0 :             || (c >= 0x0370 && c <= 0x037D)
    6214           0 :             || (c >= 0x037F && c <= 0x1FFF)
    6215           0 :             || (c >= 0x200C && c <= 0x200D)
    6216           0 :             || (c >= 0x2070 && c <= 0x218F)
    6217           0 :             || (c >= 0x2C00 && c <= 0x2FEF)
    6218           0 :             || (c >= 0x3001 && c <= 0xDFFF) // includes 0x10000 to 0xEFFFF
    6219           0 :             || (c >= 0xF900 && c <= 0xFDCF)
    6220           0 :             || (c >= 0xFDF0 && c <= 0xFFFD)
    6221           0 :             || c == '_')
    6222             :             {
    6223             :                 for(;;)
    6224             :                 {
    6225           0 :                     c = getc();
    6226           0 :                     if(c == END_OF_PATH)
    6227             :                     {
    6228           0 :                         break;
    6229             :                     }
    6230           0 :                     if((c < 'a'    || c > 'z')
    6231           0 :                     && (c < 'A'    || c > 'Z')
    6232           0 :                     && (c < '0'    || c > '9')
    6233           0 :                     && (c < 0x00C0 || c > 0x00D6)
    6234           0 :                     && (c < 0x00D8 || c > 0x00F6)
    6235           0 :                     && (c < 0x00F8 || c > 0x02FF)
    6236           0 :                     && (c < 0x0300 || c > 0x037D)
    6237           0 :                     && (c < 0x037F || c > 0x1FFF)
    6238           0 :                     && (c < 0x200C || c > 0x200D)
    6239           0 :                     && (c < 0x203F || c > 0x2040)
    6240           0 :                     && (c < 0x2070 || c > 0x218F)
    6241           0 :                     && (c < 0x2C00 || c > 0x2FEF)
    6242           0 :                     && (c < 0x3001 || c > 0xDFFF) // includes 0x10000 to 0xEFFFF
    6243           0 :                     && (c < 0xF900 || c > 0xFDCF)
    6244           0 :                     && (c < 0xFDF0 || c > 0xFFFD)
    6245           0 :                     && c != '_' && c != '.' && c != '-' && c != 0xB7)
    6246             :                     {
    6247           0 :                         ungetc(c);
    6248           0 :                         break;
    6249             :                     }
    6250           0 :                     f_last_token.f_string += QChar(c);
    6251             :                 }
    6252             :                 // at this point we return an NCNAME
    6253             :                 // (NC means No Colon)
    6254             :                 // what the name represents changes depending on context
    6255           0 :                 f_last_token.f_token = token_t::tok_t::TOK_NCNAME;
    6256             :             }
    6257             :             else
    6258             :             {
    6259             :                 // this won't match anything and thus return and error
    6260           0 :                 f_last_token.f_token = token_t::tok_t::TOK_INVALID;
    6261             :             }
    6262           0 :             break;
    6263             : 
    6264             :         }
    6265             :     }
    6266             : 
    6267           0 :     return f_last_token;
    6268             : }
    6269             : 
    6270             : #if 0
    6271             : /** \brief Check whether an NCNAME represents an operator.
    6272             :  *
    6273             :  * This function transforms a TOK_NCNAME token in one of the named operators:
    6274             :  *
    6275             :  * \li TOK_OPERATOR_AND
    6276             :  * \li TOK_OPERATOR_OR
    6277             :  * \li TOK_OPERATOR_DIV
    6278             :  * \li TOK_OPERATOR_MOD
    6279             :  *
    6280             :  * \note
    6281             :  * At this point the function is not being used because it is not really
    6282             :  * practical/useful.
    6283             :  *
    6284             :  * \return true if the f_last_token represents an operator.
    6285             :  */
    6286             : bool token_is_operator()
    6287             : {
    6288             :     switch(f_last_token.f_token)
    6289             :     {
    6290             :     case token_t::tok_t::TOK_NCNAME:
    6291             :         if(f_last_token.f_string == "and")
    6292             :         {
    6293             :             f_last_token.f_token = token_t::tok_t::TOK_OPERATOR_AND;
    6294             :         }
    6295             :         else if(f_last_token.f_string == "or")
    6296             :         {
    6297             :             f_last_token.f_token = token_t::tok_t::TOK_OPERATOR_OR;
    6298             :         }
    6299             :         else if(f_last_token.f_string == "div")
    6300             :         {
    6301             :             f_last_token.f_token = token_t::tok_t::TOK_OPERATOR_DIV;
    6302             :         }
    6303             :         else if(f_last_token.f_string == "mod")
    6304             :         {
    6305             :             f_last_token.f_token = token_t::tok_t::TOK_OPERATOR_MOD;
    6306             :         }
    6307             :         else
    6308             :         {
    6309             :             return false;
    6310             :         }
    6311             : #if __cplusplus >= 201700
    6312             :         [[fallthrough]];
    6313             : #endif
    6314             :     case token_t::tok_t::TOK_OPERATOR_AND:
    6315             :     case token_t::tok_t::TOK_OPERATOR_OR:
    6316             :     case token_t::tok_t::TOK_OPERATOR_MOD:
    6317             :     case token_t::tok_t::TOK_OPERATOR_DIV:
    6318             :         return true;
    6319             : 
    6320             :     default:
    6321             :         return false;
    6322             : 
    6323             :     }
    6324             : }
    6325             : #endif
    6326             : 
    6327             : 
    6328             : /** \brief Check whether an NCNAME represents a node type.
    6329             :  *
    6330             :  * This function transforms a TOK_NCNAME token in one of the node types:
    6331             :  *
    6332             :  * \li TOK_NODE_TYPE_COMMENT
    6333             :  * \li TOK_NODE_TYPE_TEXT
    6334             :  * \li TOK_NODE_TYPE_PROCESSING_INSTRUCTION
    6335             :  * \li TOK_NODE_TYPE_NODE
    6336             :  *
    6337             :  * \return true if the f_last_token represents a node type.
    6338             :  */
    6339           0 : bool token_is_node_type()
    6340             : {
    6341           0 :     switch(f_last_token.f_token)
    6342             :     {
    6343           0 :     case token_t::tok_t::TOK_NCNAME:
    6344           0 :         if(f_last_token.f_string == "comment")
    6345             :         {
    6346           0 :             f_last_token.f_token = token_t::tok_t::TOK_NODE_TYPE_COMMENT;
    6347             :         }
    6348           0 :         else if(f_last_token.f_string == "text")
    6349             :         {
    6350           0 :             f_last_token.f_token = token_t::tok_t::TOK_NODE_TYPE_TEXT;
    6351             :         }
    6352           0 :         else if(f_last_token.f_string == "processing-instruction")
    6353             :         {
    6354           0 :             f_last_token.f_token = token_t::tok_t::TOK_NODE_TYPE_PROCESSING_INSTRUCTION;
    6355             :         }
    6356           0 :         else if(f_last_token.f_string == "node")
    6357             :         {
    6358           0 :             f_last_token.f_token = token_t::tok_t::TOK_NODE_TYPE_NODE;
    6359             :         }
    6360             :         else
    6361             :         {
    6362           0 :             return false;
    6363             :         }
    6364             : #if __cplusplus >= 201700
    6365             :         [[fallthrough]];
    6366             : #endif
    6367             :     case token_t::tok_t::TOK_NODE_TYPE_COMMENT:
    6368             :     case token_t::tok_t::TOK_NODE_TYPE_TEXT:
    6369             :     case token_t::tok_t::TOK_NODE_TYPE_PROCESSING_INSTRUCTION:
    6370             :     case token_t::tok_t::TOK_NODE_TYPE_NODE:
    6371           0 :         return true;
    6372             : 
    6373           0 :     default:
    6374           0 :         return false;
    6375             : 
    6376             :     }
    6377             : }
    6378             : 
    6379             : /** \brief Check whether an NCNAME represents an axis.
    6380             :  *
    6381             :  * This function transforms a TOK_NCNAME token in one of the axis types:
    6382             :  *
    6383             :  * \li TOK_AXIS_NAME_ANCESTOR
    6384             :  * \li TOK_AXIS_NAME_ANCESTOR_OR_SELF
    6385             :  * \li TOK_AXIS_NAME_ATTRIBUTE
    6386             :  * \li TOK_AXIS_NAME_CHILD
    6387             :  * \li TOK_AXIS_NAME_DESCENDANT
    6388             :  * \li TOK_AXIS_NAME_DESCENDANT_OR_SELF
    6389             :  * \li TOK_AXIS_NAME_FOLLOWING
    6390             :  * \li TOK_AXIS_NAME_FOLLOWING_SIBLING
    6391             :  * \li TOK_AXIS_NAME_NAMESPACE
    6392             :  * \li TOK_AXIS_NAME_PARENT
    6393             :  * \li TOK_AXIS_NAME_PRECEDING
    6394             :  * \li TOK_AXIS_NAME_PRECEDING_SIBLING
    6395             :  * \li TOK_AXIS_NAME_SELF
    6396             :  *
    6397             :  */
    6398           0 : bool token_is_axis_name()
    6399             : {
    6400           0 :     switch(f_last_token.f_token)
    6401             :     {
    6402           0 :     case token_t::tok_t::TOK_NCNAME:
    6403             :         // TODO: add one more level to test the first letter really fast
    6404           0 :         if(f_last_token.f_string == "ancestor")
    6405             :         {
    6406           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_ANCESTOR;
    6407             :         }
    6408           0 :         else if(f_last_token.f_string == "ancestor-or-self")
    6409             :         {
    6410           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_ANCESTOR_OR_SELF;
    6411             :         }
    6412           0 :         else if(f_last_token.f_string == "attribute")
    6413             :         {
    6414           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_ATTRIBUTE;
    6415             :         }
    6416           0 :         else if(f_last_token.f_string == "child")
    6417             :         {
    6418           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_CHILD;
    6419             :         }
    6420           0 :         else if(f_last_token.f_string == "descendant")
    6421             :         {
    6422           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_DESCENDANT;
    6423             :         }
    6424           0 :         else if(f_last_token.f_string == "descendant-or-self")
    6425             :         {
    6426           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_DESCENDANT_OR_SELF;
    6427             :         }
    6428           0 :         else if(f_last_token.f_string == "following")
    6429             :         {
    6430           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_FOLLOWING;
    6431             :         }
    6432           0 :         else if(f_last_token.f_string == "following-sibling")
    6433             :         {
    6434           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_FOLLOWING_SIBLING;
    6435             :         }
    6436           0 :         else if(f_last_token.f_string == "namespace")
    6437             :         {
    6438           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_NAMESPACE;
    6439             :         }
    6440           0 :         else if(f_last_token.f_string == "parent")
    6441             :         {
    6442           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_PARENT;
    6443             :         }
    6444           0 :         else if(f_last_token.f_string == "preceding")
    6445             :         {
    6446           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_PRECEDING;
    6447             :         }
    6448           0 :         else if(f_last_token.f_string == "preceding-sibling")
    6449             :         {
    6450           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_PRECEDING_SIBLING;
    6451             :         }
    6452           0 :         else if(f_last_token.f_string == "self")
    6453             :         {
    6454           0 :             f_last_token.f_token = token_t::tok_t::TOK_AXIS_NAME_SELF;
    6455             :         }
    6456             : #if __cplusplus >= 201700
    6457             :         [[fallthrough]];
    6458             : #endif
    6459             :     case token_t::tok_t::TOK_AXIS_NAME_ANCESTOR:
    6460             :     case token_t::tok_t::TOK_AXIS_NAME_ANCESTOR_OR_SELF:
    6461             :     case token_t::tok_t::TOK_AXIS_NAME_ATTRIBUTE:
    6462             :     case token_t::tok_t::TOK_AXIS_NAME_CHILD:
    6463             :     case token_t::tok_t::TOK_AXIS_NAME_DESCENDANT:
    6464             :     case token_t::tok_t::TOK_AXIS_NAME_DESCENDANT_OR_SELF:
    6465             :     case token_t::tok_t::TOK_AXIS_NAME_FOLLOWING:
    6466             :     case token_t::tok_t::TOK_AXIS_NAME_FOLLOWING_SIBLING:
    6467             :     case token_t::tok_t::TOK_AXIS_NAME_NAMESPACE:
    6468             :     case token_t::tok_t::TOK_AXIS_NAME_PARENT:
    6469             :     case token_t::tok_t::TOK_AXIS_NAME_PRECEDING:
    6470             :     case token_t::tok_t::TOK_AXIS_NAME_PRECEDING_SIBLING:
    6471             :     case token_t::tok_t::TOK_AXIS_NAME_SELF:
    6472           0 :         return true;
    6473             : 
    6474           0 :     default:
    6475           0 :         return false;
    6476             : 
    6477             :     }
    6478             : }
    6479             : 
    6480           0 : void add_to_program(QDomXPath::instruction_t inst)
    6481             : {
    6482           0 :     f_program.push_back(inst);
    6483           0 : }
    6484             : 
    6485           0 : void append_instruction(QDomXPath::instruction_t inst)
    6486             : {
    6487           0 :     add_to_program(inst);
    6488             : 
    6489           0 :     if(f_show_commands)
    6490             :     {
    6491           0 :         disassemble_instruction(f_program.size() - 1);
    6492             :     }
    6493           0 : }
    6494             : 
    6495           0 : void append_push_string(const QString& string)
    6496             : {
    6497           0 :     int offset(f_program.size());
    6498             : 
    6499             :     // TODO: make sure that an NCNAME can be pushed as a string instead
    6500             :     //       of an NCNAME
    6501           0 :     if(string.isEmpty())
    6502             :     {
    6503             :         // push_empty_string
    6504           0 :         add_to_program(INST_PUSH_EMPTY_STRING);
    6505             :     }
    6506           0 :     else if(string == "*")
    6507             :     {
    6508             :         // push_any
    6509           0 :         add_to_program(INST_PUSH_ANY_STRING);
    6510             :     }
    6511             :     else
    6512             :     {
    6513             :         // push_string
    6514           0 :         std::string str(string.toUtf8().data());
    6515           0 :         const size_t imax(str.length());
    6516           0 :         if(imax < 256)
    6517             :         {
    6518           0 :             add_to_program(INST_PUSH_SMALL_STRING);
    6519           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax));
    6520             :             // TODO: use memcpy
    6521           0 :             for(size_t i(0); i < imax; ++i)
    6522             :             {
    6523           0 :                 add_to_program(str[i]);
    6524             :             }
    6525             :         }
    6526           0 :         else if(imax < 65536)
    6527             :         {
    6528           0 :             add_to_program(INST_PUSH_MEDIUM_STRING);
    6529           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax >> 8));
    6530           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax));
    6531             :             // TODO: use memcpy
    6532           0 :             for(size_t i(0); i < imax; ++i)
    6533             :             {
    6534           0 :                 add_to_program(str[i]);
    6535             :             }
    6536             :         }
    6537             :         else
    6538             :         {
    6539           0 :             add_to_program(INST_PUSH_LARGE_STRING);
    6540           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax >> 24));
    6541           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax >> 16));
    6542           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax >> 8));
    6543           0 :             add_to_program(static_cast<QDomXPath::instruction_t>(imax));
    6544             :             // TODO: use memcpy
    6545           0 :             for(size_t i(0); i < imax; ++i)
    6546             :             {
    6547           0 :                 add_to_program(str[i]);
    6548             :             }
    6549             :         }
    6550             :     }
    6551             : 
    6552           0 :     if(f_show_commands)
    6553             :     {
    6554           0 :         disassemble_instruction(offset);
    6555             :     }
    6556           0 : }
    6557             : 
    6558             : 
    6559           0 : void append_push_boolean(const bool boolean)
    6560             : {
    6561             :     // note: I used a terciary here, but that prevents the compiler from
    6562             :     //       optimizing the INST_PUSH_TRUE/FALSE and the link fails!?
    6563           0 :     if(boolean)
    6564             :     {
    6565           0 :         append_instruction(INST_PUSH_TRUE);
    6566             :     }
    6567             :     else
    6568             :     {
    6569           0 :         append_instruction(INST_PUSH_FALSE);
    6570             :     }
    6571           0 : }
    6572             : 
    6573             : 
    6574           0 : void append_push_integer(const int64_t integer)
    6575             : {
    6576           0 :     int offset(f_program.size());
    6577             : 
    6578           0 :     if(integer == 0)
    6579             :     {
    6580           0 :         add_to_program(INST_PUSH_ZERO);
    6581             :     }
    6582           0 :     else if(integer >= 0 && integer < 256)
    6583             :     {
    6584           0 :         add_to_program(INST_PUSH_BYTE);
    6585           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6586             :     }
    6587           0 :     else if(integer >= -256 && integer < 0)
    6588             :     {
    6589           0 :         add_to_program(INST_PUSH_NEGATIVE_BYTE);
    6590           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6591             :     }
    6592           0 :     else if(integer >= 0 && integer < 65536)
    6593             :     {
    6594           0 :         add_to_program(INST_PUSH_SHORT);
    6595           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 8));
    6596           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6597             :     }
    6598           0 :     else if(integer >= -65536 && integer < 0)
    6599             :     {
    6600           0 :         add_to_program(INST_PUSH_NEGATIVE_SHORT);
    6601           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 8));
    6602           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6603             :     }
    6604           0 :     else if(integer >= 0 && integer < 0x100000000LL)
    6605             :     {
    6606           0 :         add_to_program(INST_PUSH_LONG);
    6607           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 24));
    6608           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 16));
    6609           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 8));
    6610           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6611             :     }
    6612           0 :     else if(integer >= -0x100000000LL && integer < 0)
    6613             :     {
    6614           0 :         add_to_program(INST_PUSH_NEGATIVE_LONG);
    6615           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 24));
    6616           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 16));
    6617           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 8));
    6618           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6619             :     }
    6620             :     else
    6621             :     {
    6622           0 :         add_to_program(INST_PUSH_LONGLONG);
    6623           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 56));
    6624           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 48));
    6625           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 40));
    6626           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 32));
    6627           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 24));
    6628           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 16));
    6629           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer >> 8));
    6630           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(integer));
    6631             :     }
    6632             : 
    6633           0 :     if(f_show_commands)
    6634             :     {
    6635           0 :         disassemble_instruction(offset);
    6636             :     }
    6637           0 : }
    6638             : 
    6639           0 : void append_push_integer(node_type_t const type)
    6640             : {
    6641           0 :     append_push_integer(static_cast<int64_t>(type));
    6642           0 : }
    6643             : 
    6644           0 : void append_push_integer(axis_t const type)
    6645             : {
    6646           0 :     append_push_integer(static_cast<int64_t>(type));
    6647           0 : }
    6648             : 
    6649           0 : void append_push_integer(internal_func_t const type)
    6650             : {
    6651           0 :     append_push_integer(static_cast<int64_t>(type));
    6652           0 : }
    6653             : 
    6654           0 : void append_push_double(double const real)
    6655             : {
    6656           0 :     int offset(f_program.size());
    6657             : 
    6658             : #pragma GCC diagnostic push
    6659             : #pragma GCC diagnostic ignored "-Wfloat-equal"
    6660           0 :     if(real == 0.0)
    6661             : #pragma GCC diagnostic pop
    6662             :     {
    6663           0 :         add_to_program(INST_PUSH_DOUBLE_ZERO);
    6664             :     }
    6665             :     else
    6666             :     {
    6667           0 :         add_to_program(INST_PUSH_DOUBLE);
    6668             :         union
    6669             :         {
    6670             :             uint64_t    f_int;
    6671             :             double      f_dbl;
    6672             :         } convert;
    6673           0 :         convert.f_dbl = real;
    6674           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 56));
    6675           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 48));
    6676           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 40));
    6677           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 32));
    6678           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 24));
    6679           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 16));
    6680           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int >> 8));
    6681           0 :         add_to_program(static_cast<QDomXPath::instruction_t>(convert.f_int));
    6682             :     }
    6683             : 
    6684           0 :     if(f_show_commands)
    6685             :     {
    6686           0 :         disassemble_instruction(offset);
    6687             :     }
    6688           0 : }
    6689             : 
    6690           0 : void append_push_token(const token_t& token)
    6691             : {
    6692           0 :     switch(token.f_token)
    6693             :     {
    6694           0 :     case token_t::tok_t::TOK_ASTERISK:
    6695           0 :         append_push_string("*");
    6696           0 :         break;
    6697             : 
    6698           0 :     case token_t::tok_t::TOK_STRING:
    6699             :     case token_t::tok_t::TOK_PREFIX: // this is like a string
    6700             :     case token_t::tok_t::TOK_NCNAME: // this can be a lie (in case of variable names, it can include a colon)
    6701           0 :         append_push_string(token.f_string);
    6702           0 :         break;
    6703             : 
    6704           0 :     case token_t::tok_t::TOK_INTEGER:
    6705           0 :         append_push_integer(token.f_integer);
    6706           0 :         break;
    6707             : 
    6708           0 :     case token_t::tok_t::TOK_REAL:
    6709           0 :         append_push_double(token.f_real);
    6710           0 :         break;
    6711             : 
    6712           0 :     default:
    6713           0 :         throw QDomXPathException_InternalError(QString("unexpected token type (%1/%2) in an append_push_token() call").arg(static_cast<int>(token.f_token)).arg(token.f_string));
    6714             : 
    6715             :     }
    6716           0 : }
    6717             : 
    6718             : void append_function(const QDomXPath::program_t& function)
    6719             : {
    6720             :     const size_t size(function.size());
    6721             :     if(size < 65536)
    6722             :     {
    6723             :         append_instruction(INST_SMALL_FUNCTION);
    6724             :         append_instruction(static_cast<QDomXPath::instruction_t>(size >> 8));
    6725             :         append_instruction(static_cast<QDomXPath::instruction_t>(size));
    6726             :     }
    6727             :     else
    6728             :     {
    6729             :         append_instruction(INST_LARGE_FUNCTION);
    6730             :         append_instruction(static_cast<QDomXPath::instruction_t>(size >> 24));
    6731             :         append_instruction(static_cast<QDomXPath::instruction_t>(size >> 16));
    6732             :         append_instruction(static_cast<QDomXPath::instruction_t>(size >> 8));
    6733             :         append_instruction(static_cast<QDomXPath::instruction_t>(size));
    6734             :     }
    6735             :     f_program += function;
    6736             : }
    6737             : 
    6738             : 
    6739           0 : void append_axis(const token_t& axis, const token_t& prefix, const token_t& local_part)
    6740             : {
    6741             :     // if the prefix is marked as "undefined" then we have a NodeType
    6742             :     // instead of a name
    6743           0 :     if(prefix.f_token == token_t::tok_t::TOK_UNDEFINED)
    6744             :     {
    6745             :         // Axis '::' NodeType '(' ')'
    6746           0 :         switch(local_part.f_token)
    6747             :         {
    6748           0 :         case token_t::tok_t::TOK_NODE_TYPE_COMMENT:                 append_push_integer(node_type_t::NODE_TYPE_COMMENT);                 break;
    6749           0 :         case token_t::tok_t::TOK_NODE_TYPE_NODE:                    append_push_integer(node_type_t::NODE_TYPE_NODE);                    break;
    6750           0 :         case token_t::tok_t::TOK_NODE_TYPE_PROCESSING_INSTRUCTION:  append_push_integer(node_type_t::NODE_TYPE_PROCESSING_INSTRUCTION);  break;
    6751           0 :         case token_t::tok_t::TOK_NODE_TYPE_TEXT:                    append_push_integer(node_type_t::NODE_TYPE_TEXT);                    break;
    6752             : 
    6753           0 :         default:
    6754           0 :             throw QDomXPathException_InvalidError("invalid node type");
    6755             : 
    6756             :         }
    6757             : 
    6758             :         // if 'processing-instruction' then we could have a string here
    6759             :         // if empty, then no name was specified to the NodeType '(' ')'
    6760           0 :         append_push_string(axis.f_string);
    6761             :     }
    6762             :     else
    6763             :     {
    6764             :         // push the name, it may be "*:*" if the node type is specified
    6765           0 :         append_push_token(local_part);
    6766           0 :         append_push_token(prefix);
    6767             :     }
    6768             : 
    6769             :     // TODO: node type
    6770             :  
    6771           0 :     switch(axis.f_token)
    6772             :     {
    6773           0 :     case token_t::tok_t::TOK_AXIS_NAME_ANCESTOR:           append_push_integer(axis_t::AXIS_ANCESTOR);             break;
    6774           0 :     case token_t::tok_t::TOK_AXIS_NAME_ANCESTOR_OR_SELF:   append_push_integer(axis_t::AXIS_ANCESTOR_OR_SELF);     break;
    6775           0 :     case token_t::tok_t::TOK_AXIS_NAME_ATTRIBUTE:          append_push_integer(axis_t::AXIS_ATTRIBUTE);            break;
    6776           0 :     case token_t::tok_t::TOK_AXIS_NAME_CHILD:              append_push_integer(axis_t::AXIS_CHILD);                break;
    6777           0 :     case token_t::tok_t::TOK_AXIS_NAME_DESCENDANT:         append_push_integer(axis_t::AXIS_DESCENDANT);           break;
    6778           0 :     case token_t::tok_t::TOK_AXIS_NAME_DESCENDANT_OR_SELF: append_push_integer(axis_t::AXIS_DESCENDANT_OR_SELF);   break;
    6779           0 :     case token_t::tok_t::TOK_AXIS_NAME_FOLLOWING:          append_push_integer(axis_t::AXIS_FOLLOWING);            break;
    6780           0 :     case token_t::tok_t::TOK_AXIS_NAME_FOLLOWING_SIBLING:  append_push_integer(axis_t::AXIS_FOLLOWING_SIBLING);    break;
    6781           0 :     case token_t::tok_t::TOK_AXIS_NAME_NAMESPACE:          append_push_integer(axis_t::AXIS_NAMESPACE);            break;
    6782           0 :     case token_t::tok_t::TOK_AXIS_NAME_PARENT:             append_push_integer(axis_t::AXIS_PARENT);               break;
    6783           0 :     case token_t::tok_t::TOK_AXIS_NAME_PRECEDING:          append_push_integer(axis_t::AXIS_PRECEDING);            break;
    6784           0 :     case token_t::tok_t::TOK_AXIS_NAME_PRECEDING_SIBLING:  append_push_integer(axis_t::AXIS_PRECEDING_SIBLING);    break;
    6785           0 :     case token_t::tok_t::TOK_AXIS_NAME_SELF:               append_push_integer(axis_t::AXIS_SELF);                 break;
    6786             : 
    6787           0 :     default:
    6788           0 :         throw QDomXPathException_InvalidError("invalid axis type");
    6789             : 
    6790             :     }
    6791             : 
    6792           0 :     append_instruction(INST_AXIS);
    6793           0 : }
    6794             : 
    6795             : 
    6796             : void append_push_for_jump(const QString& label)
    6797             : {
    6798             :     if(label.isEmpty())
    6799             :     {
    6800             :         throw QDomXPathException_InternalError("pushing for a future label with an empty string is not supported");
    6801             :     }
    6802             :     if(f_show_commands)
    6803             :     {
    6804             :         std::cout << "=== push for jump (" << f_program.size() << ")\n";
    6805             :     }
    6806             :     f_future_labels[label].push_back(f_program.size());
    6807             :     append_push_integer(0x1111); // reserve 2 bytes for pc
    6808             : }
    6809             : 
    6810             : 
    6811             : void mark_with_label(const QString& label)
    6812             : {
    6813             :     int offset(f_program.size());
    6814             :     f_labels[label] = offset;
    6815             : 
    6816             :     if(f_future_labels.contains(label))
    6817             :     {
    6818             :         future_labels_t::iterator future(f_future_labels.find(label));
    6819             :         const int imax((*future).size());
    6820             :         for(int i(0); i < imax; ++i)
    6821             :         {
    6822             :             int pc((*future)[i]);
    6823             :             f_program[pc + 1] = static_cast<instruction_t>(offset >> 8);
    6824             :             f_program[pc + 2] = static_cast<instruction_t>(offset);
    6825             : 
    6826             :             if(f_show_commands)
    6827             :             {
    6828             :                 std::cout << "# Fix offset -- ";
    6829             :                 disassemble_instruction(pc);
    6830             :             }
    6831             :         }
    6832             :         f_future_labels.erase(future);
    6833             :     }
    6834             : }
    6835             : 
    6836             : 
    6837             : 
    6838           0 : void unary_expr()
    6839             : {
    6840           0 :     int negate(0);
    6841             :     for(;;)
    6842             :     {
    6843           0 :         if(f_last_token.f_token == token_t::tok_t::TOK_MINUS)
    6844             :         {
    6845           0 :             negate ^= 1;
    6846             :         }
    6847           0 :         else if(f_last_token.f_token != token_t::tok_t::TOK_PLUS) // XPath 2.0 allows unary '+'
    6848             :         {
    6849           0 :             break;
    6850             :         }
    6851           0 :         get_token();
    6852             :     }
    6853           0 :     union_expr();
    6854           0 :     if(negate)
    6855             :     {
    6856           0 :         append_instruction(INST_NEGATE);
    6857             :     }
    6858           0 : }
    6859             : 
    6860           0 : void multiplicative_expr()
    6861             : {
    6862           0 :     unary_expr();
    6863             :     for(;;)
    6864             :     {
    6865           0 :         instruction_t inst(INST_END);
    6866           0 :         switch(f_last_token.f_token)
    6867             :         {
    6868           0 :         case token_t::tok_t::TOK_ASTERISK:
    6869           0 :             inst = INST_MULTIPLY;
    6870           0 :             break;
    6871             : 
    6872           0 :         case token_t::tok_t::TOK_NCNAME:
    6873           0 :             if(f_last_token.f_string == "div")
    6874             :             {
    6875           0 :                 inst = INST_DIVIDE;
    6876             :             }
    6877           0 :             else if(f_last_token.f_string == "idiv")
    6878             :             {
    6879           0 :                 inst = INST_IDIVIDE;
    6880             :             }
    6881           0 :             else if(f_last_token.f_string == "mod")
    6882             :             {
    6883           0 :                 inst = INST_MODULO;
    6884             :             }
    6885             :             else
    6886             :             {
    6887           0 :                 return;
    6888             :             }
    6889           0 :             break;
    6890             : 
    6891           0 :         default:
    6892           0 :             return;
    6893             : 
    6894             :         }
    6895           0 :         get_token();
    6896           0 :         unary_expr();
    6897           0 :         append_instruction(inst);
    6898           0 :     }
    6899             : }
    6900             : 
    6901           0 : void additive_expr()
    6902             : {
    6903           0 :     multiplicative_expr();
    6904             :     for(;;)
    6905             :     {
    6906           0 :         instruction_t inst(INST_END);
    6907           0 :         switch(f_last_token.f_token)
    6908             :         {
    6909           0 :         case token_t::tok_t::TOK_PLUS:
    6910           0 :             inst = INST_ADD;
    6911           0 :             break;
    6912             : 
    6913           0 :         case token_t::tok_t::TOK_MINUS:
    6914           0 :             inst = INST_SUBTRACT;
    6915           0 :             break;
    6916             : 
    6917           0 :         default:
    6918           0 :             return;
    6919             : 
    6920             :         }
    6921           0 :         get_token();
    6922           0 :         multiplicative_expr();
    6923           0 :         append_instruction(inst);
    6924           0 :     }
    6925             : }
    6926             : 
    6927           0 : void relational_expr()
    6928             : {
    6929           0 :     additive_expr();
    6930             :     for(;;)
    6931             :     {
    6932           0 :         instruction_t inst(INST_END);
    6933           0 :         switch(f_last_token.f_token)
    6934             :         {
    6935           0 :         case token_t::tok_t::TOK_LESS_THAN:
    6936           0 :             inst = INST_LESS_THAN;
    6937           0 :             break;
    6938             : 
    6939           0 :         case token_t::tok_t::TOK_LESS_OR_EQUAL:
    6940           0 :             inst = INST_LESS_OR_EQUAL;
    6941           0 :             break;
    6942             : 
    6943           0 :         case token_t::tok_t::TOK_GREATER_THAN:
    6944           0 :             inst = INST_GREATER_THAN;
    6945           0 :             break;
    6946             : 
    6947           0 :         case token_t::tok_t::TOK_GREATER_OR_EQUAL:
    6948           0 :             inst = INST_GREATER_OR_EQUAL;
    6949           0 :             break;
    6950             : 
    6951           0 :         default:
    6952           0 :             return;
    6953             : 
    6954             :         }
    6955           0 :         get_token();
    6956           0 :         additive_expr();
    6957           0 :         append_instruction(inst);
    6958           0 :     }
    6959             : }
    6960             : 
    6961           0 : void equality_expr()
    6962             : {
    6963           0 :     relational_expr();
    6964             :     for(;;)
    6965             :     {
    6966           0 :         instruction_t inst(INST_END);
    6967           0 :         switch(f_last_token.f_token)
    6968             :         {
    6969           0 :         case token_t::tok_t::TOK_EQUAL:
    6970           0 :             inst = INST_EQUAL;
    6971           0 :             break;
    6972             : 
    6973           0 :         case token_t::tok_t::TOK_NOT_EQUAL:
    6974           0 :             inst = INST_NOT_EQUAL;
    6975           0 :             break;
    6976             : 
    6977           0 :         default:
    6978           0 :             return;
    6979             : 
    6980             :         }
    6981           0 :         get_token();
    6982           0 :         relational_expr();
    6983           0 :         append_instruction(inst);
    6984           0 :     }
    6985             : }
    6986             : 
    6987           0 : void and_expr()
    6988             : {
    6989           0 :     equality_expr();
    6990           0 :     while(f_last_token.f_token == token_t::tok_t::TOK_NCNAME && f_last_token.f_string == "and")
    6991             :     {
    6992           0 :         get_token();
    6993           0 :         equality_expr();
    6994           0 :         append_instruction(INST_AND);
    6995             :     }
    6996           0 : }
    6997             : 
    6998             : /** \brief The OrExpr
    6999             :  *
    7000             :  * The OrExpr is a one to one equivalent to the Expr.
    7001             :  *
    7002             :  * It appears between parenthesis from within a location path.
    7003             :  */
    7004           0 : void or_expr()
    7005             : {
    7006           0 :     and_expr();
    7007           0 :     while(f_last_token.f_token == token_t::tok_t::TOK_NCNAME && f_last_token.f_string == "or")
    7008             :     {
    7009           0 :         get_token();
    7010           0 :         and_expr();
    7011           0 :         append_instruction(INST_OR);
    7012             :     }
    7013           0 : }
    7014             : 
    7015             : 
    7016             : /** \brief Parse a function call parameters.
    7017             :  *
    7018             :  * This function handles internal function calls such as fn:position().
    7019             :  *
    7020             :  * If the prefix is not defined, we use 'fn' as the default. I'm not
    7021             :  * totally sure that this is correct since some internal functions
    7022             :  * are defined with the xs prefix. (the op:... functions are operators
    7023             :  * only so it wouldn't apply as a default anyway.)
    7024             :  *
    7025             :  * Note that for speed a certain number of internal functions are fully
    7026             :  * parsed here and transformed into code directly instead of an INST_CALL
    7027             :  * instruction.
    7028             :  *
    7029             :  * \param[in] prefix_token  The prefix of the function, if "*" or "", then "fn" is used
    7030             :  * \param[in] local_part  The name of the function (i.e. "position", "last", ...)
    7031             :  */
    7032           0 : void function_call(token_t prefix_token, token_t local_part)
    7033             : {
    7034             :     // the last token read was the '(', now we read the arguments which
    7035             :     // each are full expressions:
    7036             :     //      Argument ::= Expr
    7037             :     //      Expr ::= OrExpr
    7038             : 
    7039             :     // skip the '('
    7040           0 :     get_token();
    7041             : 
    7042             :     // make sure we have the default namespace if the user did not specify it
    7043           0 :     if(prefix_token.f_string == "*" || prefix_token.f_string.isEmpty())
    7044             :     {
    7045             :         // the default namespace is "fn"
    7046           0 :         prefix_token.f_string = "fn";
    7047             :     }
    7048             : 
    7049             :     // set of internal functions that we can transform in one or a very few
    7050             :     // basic instructions
    7051           0 :     if(prefix_token.f_string == "fn")
    7052             :     {
    7053           0 :         switch(local_part.f_string[0].unicode())
    7054             :         {
    7055           0 :         case 'c':
    7056           0 :             if(local_part.f_string == "ceiling")
    7057             :             {
    7058           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7059             :                 {
    7060           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the ceiling() function");
    7061             :                 }
    7062           0 :                 or_expr();
    7063           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7064             :                 {
    7065           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the ceiling() function");
    7066             :                 }
    7067           0 :                 append_instruction(INST_CEILING);
    7068             :                 // skip the ')'
    7069           0 :                 get_token();
    7070           0 :                 return;
    7071             :             }
    7072           0 :             if(local_part.f_string == "count")
    7073             :             {
    7074           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7075             :                 {
    7076           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the count() function");
    7077             :                 }
    7078           0 :                 or_expr();
    7079           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7080             :                 {
    7081           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the count() function");
    7082             :                 }
    7083           0 :                 append_instruction(INST_NODE_SET_SIZE);
    7084             :                 // skip the ')'
    7085           0 :                 get_token();
    7086           0 :                 return;
    7087             :             }
    7088           0 :             break;
    7089             : 
    7090           0 :         case 'e':
    7091           0 :             if(local_part.f_string == "empty"
    7092           0 :             || local_part.f_string == "exists")
    7093             :             {
    7094           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7095             :                 {
    7096           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the empty() function");
    7097             :                 }
    7098           0 :                 or_expr();
    7099           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7100             :                 {
    7101           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the empty() function");
    7102             :                 }
    7103           0 :                 append_instruction(INST_NODE_SET_SIZE);
    7104           0 :                 append_push_integer(0);
    7105           0 :                 append_instruction(INST_EQUAL);
    7106             :                 // skip the ')'
    7107           0 :                 get_token();
    7108           0 :                 return;
    7109             :             }
    7110           0 :             break;
    7111             : 
    7112           0 :         case 'f':
    7113           0 :             if(local_part.f_string == "false")
    7114             :             {
    7115           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7116             :                 {
    7117           0 :                     throw QDomXPathException_SyntaxError("expected ')' immediately for the false() function does not accept parameters");
    7118             :                 }
    7119           0 :                 append_push_boolean(false);
    7120             :                 // skip the ')'
    7121           0 :                 get_token();
    7122           0 :                 return;
    7123             :             }
    7124           0 :             if(local_part.f_string == "floor")
    7125             :             {
    7126           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7127             :                 {
    7128           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the floor() function");
    7129             :                 }
    7130           0 :                 or_expr();
    7131           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7132             :                 {
    7133           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the floor() function");
    7134             :                 }
    7135           0 :                 append_instruction(INST_FLOOR);
    7136             :                 // skip the ')'
    7137           0 :                 get_token();
    7138           0 :                 return;
    7139             :             }
    7140           0 :             break;
    7141             : 
    7142           0 :         case 'l':
    7143           0 :             if(local_part.f_string == "last")
    7144             :             {
    7145           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7146             :                 {
    7147           0 :                     throw QDomXPathException_SyntaxError("expected ')' immediately for the last() function does not accept parameters");
    7148             :                 }
    7149           0 :                 append_instruction(INST_GET_NODE_SET);
    7150           0 :                 append_instruction(INST_NODE_SET_SIZE);
    7151             :                 // skip the ')'
    7152           0 :                 get_token();
    7153           0 :                 return;
    7154             :             }
    7155           0 :             break;
    7156             : 
    7157           0 :         case 'n':
    7158           0 :             if(local_part.f_string == "not")
    7159             :             {
    7160           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7161             :                 {
    7162           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the not() function");
    7163             :                 }
    7164           0 :                 or_expr();
    7165           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7166             :                 {
    7167           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the not() function");
    7168             :                 }
    7169           0 :                 append_instruction(INST_NOT);
    7170             :                 // skip the ')'
    7171           0 :                 get_token();
    7172           0 :                 return;
    7173             :             }
    7174           0 :             break;
    7175             : 
    7176           0 :         case 'p':
    7177           0 :             if(local_part.f_string == "position")
    7178             :             {
    7179           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7180             :                 {
    7181           0 :                     throw QDomXPathException_SyntaxError("expected ')' immediately for the position() function does not accept parameters");
    7182             :                 }
    7183           0 :                 append_instruction(INST_GET_POSITION);
    7184             :                 // skip the ')'
    7185           0 :                 get_token();
    7186           0 :                 return;
    7187             :             }
    7188           0 :             break;
    7189             : 
    7190           0 :         case 'r':
    7191           0 :             if(local_part.f_string == "round")
    7192             :             {
    7193           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7194             :                 {
    7195           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the round() function");
    7196             :                 }
    7197           0 :                 or_expr();
    7198           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7199             :                 {
    7200           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the round() function");
    7201             :                 }
    7202           0 :                 append_instruction(INST_ROUND);
    7203             :                 // skip the ')'
    7204           0 :                 get_token();
    7205           0 :                 return;
    7206             :             }
    7207           0 :             break;
    7208             : 
    7209           0 :         case 's':
    7210           0 :             if(local_part.f_string == "string-length")
    7211             :             {
    7212             :                 // TODO add support for '.' instead of an argument
    7213           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7214             :                 {
    7215           0 :                     throw QDomXPathException_SyntaxError("expected one parameter for the string-length() function");
    7216             :                 }
    7217           0 :                 or_expr();
    7218           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7219             :                 {
    7220           0 :                     throw QDomXPathException_SyntaxError("expected exactly one parameter for the string-length() function");
    7221             :                 }
    7222           0 :                 append_instruction(INST_STRING_LENGTH);
    7223             :                 // skip the ')'
    7224           0 :                 get_token();
    7225           0 :                 return;
    7226             :             }
    7227           0 :             break;
    7228             : 
    7229           0 :         case 't':
    7230           0 :             if(local_part.f_string == "true")
    7231             :             {
    7232           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7233             :                 {
    7234           0 :                     throw QDomXPathException_SyntaxError("expected ')' immediately for the true() function does not accept parameters");
    7235             :                 }
    7236           0 :                 append_push_boolean(true);
    7237             :                 // skip the ')'
    7238           0 :                 get_token();
    7239           0 :                 return;
    7240             :             }
    7241           0 :             break;
    7242             : 
    7243             :         }
    7244             :     }
    7245             : 
    7246           0 :     int argc(0);
    7247           0 :     append_instruction(INST_PUSH_END_OF_ARGUMENTS);
    7248           0 :     if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7249             :     {
    7250           0 :         ++argc;
    7251           0 :         or_expr();
    7252           0 :         while(f_last_token.f_token == token_t::tok_t::TOK_COMMA)
    7253             :         {
    7254           0 :             ++argc;
    7255           0 :             get_token();
    7256           0 :             or_expr();
    7257             :         }
    7258           0 :         if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7259             :         {
    7260           0 :             throw QDomXPathException_SyntaxError("expected ')' or ',' in the list of argument to a function call");
    7261             :         }
    7262             :     }
    7263             :     // skip the ')'
    7264           0 :     get_token();
    7265             : 
    7266             :     // by default we expect no parameters
    7267           0 :     int min_argc(0);
    7268           0 :     int max_argc(0);
    7269           0 :     internal_func_t f(internal_func_t::FUNC_UNKNOWN);
    7270             : 
    7271           0 :     switch(prefix_token.f_string[0].unicode())
    7272             :     {
    7273           0 :     case 'f':
    7274           0 :         if(prefix_token.f_string == "fn")
    7275             :         {
    7276           0 :             switch(local_part.f_string[0].unicode())
    7277             :             {
    7278           0 :             case 'a':
    7279           0 :                 if(local_part.f_string == "avg")
    7280             :                 {
    7281           0 :                     f = internal_func_t::FUNC_AVG;
    7282           0 :                     max_argc = -1; // any number of parameters
    7283             :                 }
    7284           0 :                 break;
    7285             : 
    7286           0 :             case 'm':
    7287           0 :                 if(local_part.f_string == "max")
    7288             :                 {
    7289           0 :                     f = internal_func_t::FUNC_MAX;
    7290           0 :                     max_argc = -1; // any number of parameters
    7291             :                 }
    7292           0 :                 else if(local_part.f_string == "min")
    7293             :                 {
    7294           0 :                     f = internal_func_t::FUNC_MIN;
    7295           0 :                     max_argc = -1; // any number of parameters
    7296             :                 }
    7297           0 :                 break;
    7298             : 
    7299           0 :             case 's':
    7300           0 :                 if(local_part.f_string == "sum")
    7301             :                 {
    7302           0 :                     f = internal_func_t::FUNC_SUM;
    7303           0 :                     max_argc = -1; // any number of parameters
    7304             :                 }
    7305           0 :                 break;
    7306             : 
    7307             :             }
    7308             :         }
    7309           0 :         break;
    7310             : 
    7311           0 :     default:
    7312           0 :         break;
    7313             : 
    7314             :     }
    7315             : 
    7316             :     // we do not yet support user defined functions
    7317           0 :     if(f == internal_func_t::FUNC_UNKNOWN)
    7318             :     {
    7319           0 :         throw QDomXPathException_UnknownFunctionError(QString("'%1' is not a known function (we may not yet support it...)")
    7320           0 :                                                     .arg(prefix_token.f_string + ":" + local_part.f_string));
    7321             :     }
    7322           0 :     if(argc < min_argc)
    7323             :     {
    7324           0 :         throw QDomXPathException_UnknownFunctionError(QString("'%1' expects at least %2 arguments, but got %3 instead")
    7325           0 :                                                     .arg(prefix_token.f_string + ":" + local_part.f_string)
    7326           0 :                                                     .arg(min_argc).arg(argc));
    7327             :     }
    7328           0 :     if(max_argc != -1 && argc > max_argc)
    7329             :     {
    7330           0 :         throw QDomXPathException_UnknownFunctionError(QString("'%1' expects at most %2 arguments, it got %3 instead")
    7331           0 :                                                     .arg(prefix_token.f_string + ":" + local_part.f_string)
    7332           0 :                                                     .arg(max_argc).arg(argc));
    7333             :     }
    7334             : 
    7335           0 :     append_push_integer(f);
    7336           0 :     append_instruction(INST_CALL);
    7337             : }
    7338             : 
    7339             : 
    7340           0 : void predicate()
    7341             : {
    7342           0 :     QString save_predicate_variable(f_predicate_variable);
    7343           0 :     ++f_label_counter;
    7344           0 :     f_predicate_variable = QString("$%1").arg(f_label_counter);
    7345             : 
    7346           0 :     append_instruction(INST_CREATE_NODE_CONTEXT);
    7347             : 
    7348             :     // we just had an axis, now we have n predicates following
    7349             :     // only the problem is that each predicate has to be applied
    7350             :     // to each node as a context node of the current state
    7351           0 :     do
    7352             :     {
    7353             :         // skip the '['
    7354           0 :         get_token();
    7355             : 
    7356             :         // 'next_node' label
    7357           0 :         const int next_node(f_program.size());
    7358             : 
    7359           0 :         append_instruction(INST_GET_CONTEXT_NODE);
    7360           0 :         append_push_string(f_predicate_variable);
    7361           0 :         append_instruction(INST_SET_VARIABLE);
    7362             : 
    7363           0 :         or_expr();
    7364           0 :         if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_SQUARE_BRACKET)
    7365             :         {
    7366           0 :             throw QDomXPathException_SyntaxError("missing ']' to close a Predicate");
    7367             :         }
    7368             : 
    7369           0 :         append_instruction(INST_PREDICATE); // "apply" predicate
    7370             :         //append_instruction(INST_NEXT_CONTEXT_NODE);
    7371           0 :         append_push_integer(next_node);
    7372           0 :         append_instruction(INST_JUMP_IF_TRUE); // next_node
    7373           0 :         append_instruction(INST_GET_RESULT);
    7374           0 :         append_instruction(INST_SET_NODE_SET);
    7375           0 :         append_instruction(INST_PUSH_EMPTY_NODE_SET);
    7376           0 :         append_instruction(INST_SET_RESULT);
    7377             : 
    7378           0 :         get_token();
    7379             :     }
    7380           0 :     while(f_last_token.f_token == token_t::tok_t::TOK_OPEN_SQUARE_BRACKET);
    7381             : 
    7382           0 :     append_instruction(INST_GET_NODE_SET);
    7383           0 :     append_instruction(INST_POP_CONTEXT); // get rid of the context
    7384             : 
    7385           0 :     f_predicate_variable = save_predicate_variable;
    7386           0 : }
    7387             : 
    7388           0 : void location_path()
    7389             : {
    7390           0 :     labels_t labels;
    7391             : 
    7392           0 :     QString predicate_variable(f_predicate_variable);
    7393           0 :     bool function_call_valid(f_last_token.f_token == token_t::tok_t::TOK_NCNAME);
    7394           0 :     bool first_round(true);
    7395             :     for(;;)
    7396             :     {
    7397           0 :         bool double_slash(false);
    7398           0 :         switch(f_last_token.f_token)
    7399             :         {
    7400           0 :         case token_t::tok_t::TOK_DOUBLE_SLASH:
    7401           0 :             double_slash = true;
    7402             : #if __cplusplus >= 201700
    7403             :             [[fallthrough]];
    7404             : #endif
    7405           0 :         case token_t::tok_t::TOK_SLASH:
    7406           0 :             if(first_round)
    7407             :             {
    7408             :                 // this is absolute, start from the root
    7409             : 
    7410             :                 // replace the current node-set into a node context
    7411             :                 // that way we can properly loop through the list of
    7412             :                 // nodes against this axis
    7413             :                 //
    7414             :                 // TODO: look into optimizating: return only one root
    7415             :                 //       per document...
    7416           0 :                 if(!predicate_variable.isEmpty())
    7417             :                 {
    7418           0 :                     append_push_string(predicate_variable);
    7419           0 :                     append_instruction(INST_GET_VARIABLE);
    7420           0 :                     predicate_variable.clear();
    7421             :                 }
    7422           0 :                 append_instruction(INST_CREATE_NODE_CONTEXT);
    7423           0 :                 labels.push_back(f_program.size());
    7424           0 :                 append_instruction(INST_GET_CONTEXT_NODE);
    7425             : 
    7426           0 :                 append_instruction(INST_ROOT);
    7427             :             }
    7428           0 :             get_token();
    7429           0 :             break;
    7430             : 
    7431           0 :         default:
    7432           0 :             if(!first_round)
    7433             :             {
    7434             :                 // anything else is not part of the location path
    7435             :                 // if we are in a relative path (this allows "/")
    7436           0 :                 goto finished;
    7437             :             }
    7438           0 :             break;
    7439             : 
    7440             :         }
    7441           0 :         bool accept_predicate(true);
    7442           0 :         first_round = false;
    7443           0 :         token_t save_token(f_last_token);
    7444           0 :         token_t axis_token;
    7445           0 :         axis_token.f_token = double_slash ? token_t::tok_t::TOK_AXIS_NAME_DESCENDANT : token_t::tok_t::TOK_AXIS_NAME_CHILD;
    7446           0 :         axis_token.f_string = double_slash ? "descendant" : "child";
    7447           0 :         token_t prefix_token;
    7448           0 :         prefix_token.f_token = token_t::tok_t::TOK_PREFIX;
    7449           0 :         prefix_token.f_string = "*";
    7450           0 :         switch(f_last_token.f_token)
    7451             :         {
    7452           0 :         case token_t::tok_t::TOK_DOT:
    7453             :             // self
    7454           0 :             save_token.f_token = token_t::tok_t::TOK_NCNAME;
    7455           0 :             save_token.f_string = "*";
    7456           0 :             axis_token.f_token = token_t::tok_t::TOK_AXIS_NAME_SELF;
    7457           0 :             axis_token.f_string = "self";
    7458           0 :             accept_predicate = false;
    7459           0 :             goto axis_apply;
    7460             : 
    7461           0 :         case token_t::tok_t::TOK_DOUBLE_DOT:
    7462             :             // parent
    7463           0 :             save_token.f_token = token_t::tok_t::TOK_NCNAME;
    7464           0 :             save_token.f_string = "*";
    7465           0 :             axis_token.f_token = token_t::tok_t::TOK_AXIS_NAME_PARENT;
    7466           0 :             axis_token.f_string = "parent";
    7467           0 :             accept_predicate = false;
    7468           0 :             goto axis_apply;
    7469             : 
    7470           0 :         case token_t::tok_t::TOK_ASTERISK:
    7471             :             // '*'  -- a name test by itself
    7472             :             // this is actually the default!
    7473           0 :             get_token();
    7474           0 :             goto axis_apply;
    7475             : 
    7476           0 :         case token_t::tok_t::TOK_AT:
    7477             :             // The '@' is the AbbreviatedAxisSpecifier
    7478             :             //     '@' NoteTest Predicate*
    7479             :             //     'attribute' :: NodeTest Predicate*
    7480           0 :             axis_token.f_token = token_t::tok_t::TOK_AXIS_NAME_ATTRIBUTE;
    7481           0 :             axis_token.f_string = "attribute";
    7482           0 :             goto axis_name_attribute;
    7483             : 
    7484           0 :         case token_t::tok_t::TOK_NCNAME:
    7485           0 :             get_token();
    7486           0 :             if(f_last_token.f_token == token_t::tok_t::TOK_DOUBLE_COLON)
    7487             :             {
    7488           0 :                 function_call_valid = false;
    7489             :                 // the NCNAME before '::' is an AxisName
    7490             :                 // AxisName '::' NoteTest Predicate*
    7491           0 :                 f_last_token = save_token;
    7492           0 :                 if(!token_is_axis_name())
    7493             :                 {
    7494           0 :                     throw QDomXPathException_SyntaxError(QString("a double colon (::) must be preceded by a valid axis name, \"%1\" was not recognized as such").arg(f_last_token.f_string));
    7495             :                 }
    7496           0 :                 axis_token = f_last_token;
    7497           0 : axis_name_attribute:
    7498           0 :                 get_token(); // NodeTest
    7499           0 :                 save_token = f_last_token;
    7500           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_ASTERISK)
    7501             :                 {
    7502             :                     // no specific prefix or local part
    7503           0 :                     get_token();
    7504           0 :                     goto axis_apply;
    7505             :                 }
    7506           0 :                 if(f_last_token.f_token != token_t::tok_t::TOK_NCNAME)
    7507             :                 {
    7508           0 :                     throw QDomXPathException_SyntaxError("a double colon (::) must be followed by an NCName or '*'");
    7509             :                 }
    7510           0 :                 get_token();
    7511             :             }
    7512           0 :             if(f_last_token.f_token == token_t::tok_t::TOK_COLON)
    7513             :             {
    7514             :                 // namespace ':' NCName
    7515             :                 // namespace ':' '*'
    7516           0 :                 prefix_token = save_token;
    7517           0 :                 get_token();
    7518           0 :                 save_token = f_last_token;
    7519           0 :                 get_token();
    7520           0 :                 switch(save_token.f_token)
    7521             :                 {
    7522           0 :                 case token_t::tok_t::TOK_ASTERISK:
    7523           0 :                     break;
    7524             : 
    7525           0 :                 case token_t::tok_t::TOK_NCNAME:
    7526           0 :                     if(function_call_valid && f_last_token.f_token == token_t::tok_t::TOK_OPEN_PARENTHESIS)
    7527             :                     {
    7528             :                         // A function name is a QName which means it can include a prefix
    7529             :                         //      Prefix ':' LocalPart '(' ... ')'
    7530           0 :                         function_call(prefix_token, save_token);
    7531           0 :                         goto finished;
    7532             :                     }
    7533           0 :                     break;
    7534             : 
    7535           0 :                 default:
    7536           0 :                     throw QDomXPathException_SyntaxError("expected an NCName or '*' after a prefix");
    7537             : 
    7538             :                 }
    7539             :             }
    7540           0 :             else if(f_last_token.f_token == token_t::tok_t::TOK_OPEN_PARENTHESIS)
    7541             :             {
    7542             :                 // in this case we have:
    7543             :                 //    NodeType '(' [...] ')'
    7544             :                 //    FunctionCall '(' ... ')'
    7545           0 :                 f_last_token = save_token;
    7546           0 :                 if(!token_is_node_type())
    7547             :                 {
    7548             :                     // Does a function call apply here?
    7549             :                     //      LocalPart '(' ... ')'
    7550           0 :                     if(function_call_valid)
    7551             :                     {
    7552             :                         // the default prefix token is "*" meaning no prefix
    7553           0 :                         function_call(prefix_token, save_token);
    7554           0 :                         goto finished;
    7555             :                     }
    7556             :                     // we got a function call here!
    7557           0 :                     throw QDomXPathException_SyntaxError("a path followed by parenthesis must be a NodeType");
    7558             :                 }
    7559             :                 // save the NodeType token
    7560           0 :                 save_token.f_token = f_last_token.f_token;
    7561           0 :                 get_token();
    7562           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_STRING)
    7563             :                 {
    7564           0 :                     if(axis_token.f_token != token_t::tok_t::TOK_NODE_TYPE_PROCESSING_INSTRUCTION)
    7565             :                     {
    7566           0 :                         throw QDomXPathException_InvalidError("only a processing-instruction NodeType can be given a Literal");
    7567             :                     }
    7568             :                     // a special case where the TOK_NODE_TYPE_PROCESSING_INSTRUCTION
    7569           0 :                     axis_token.f_string = f_last_token.f_string;
    7570           0 :                     get_token();
    7571             :                 }
    7572             :                 else
    7573             :                 {
    7574           0 :                     axis_token.f_string = "";
    7575             :                 }
    7576           0 :                 if(f_last_token.f_token == token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7577             :                 {
    7578           0 :                     throw QDomXPathException_SyntaxError("missing ')' after the NodeType definition");
    7579             :                 }
    7580           0 :                 prefix_token.f_token = token_t::tok_t::TOK_UNDEFINED;
    7581             :             }
    7582             : 
    7583           0 : axis_apply:
    7584             :             {
    7585             :                 // replace the current node-set into a node context
    7586             :                 // that way we can properly loop through the list of
    7587             :                 // nodes against this axis
    7588           0 :                 if(!predicate_variable.isEmpty())
    7589             :                 {
    7590           0 :                     append_push_string(predicate_variable);
    7591           0 :                     append_instruction(INST_GET_VARIABLE);
    7592           0 :                     predicate_variable.clear();
    7593             :                 }
    7594           0 :                 append_instruction(INST_CREATE_NODE_CONTEXT);
    7595           0 :                 labels.push_back(f_program.size());
    7596           0 :                 append_instruction(INST_GET_CONTEXT_NODE);
    7597             : 
    7598             :                 // axis_token (axis::)
    7599             :                 // prefix_token (prefix:)
    7600             :                 // save_token (path or '*' or NodeType)
    7601           0 :                 append_axis(axis_token, prefix_token, save_token);
    7602             : 
    7603           0 :                 if(accept_predicate && f_last_token.f_token == token_t::tok_t::TOK_OPEN_SQUARE_BRACKET)
    7604             :                 {
    7605             :                     // process all predicates following this step
    7606           0 :                     predicate();
    7607             :                 }
    7608             :             }
    7609           0 :             break;
    7610             : 
    7611           0 :         default:
    7612           0 :             if(!double_slash)
    7613             :             {
    7614             :                 // in case we have a double slash, the relative path is optional
    7615             :                 //break 2;
    7616           0 :                 goto finished;
    7617             :             }
    7618           0 :             throw QDomXPathException_SyntaxError("expected a relative path, none found");
    7619             : 
    7620             :         }
    7621             :         // if we loop function calls are not possible anymore
    7622           0 :         function_call_valid = false;
    7623           0 :     }
    7624             : 
    7625           0 : finished:
    7626           0 :     for(int i(labels.size() - 1); i >= 0; --i)
    7627             :     {
    7628             :         // repeat with the next node of that context
    7629           0 :         append_instruction(INST_NEXT_CONTEXT_NODE);
    7630           0 :         append_push_integer(labels[i]);
    7631           0 :         append_instruction(INST_JUMP_IF_TRUE);
    7632             : 
    7633             :         // return the result (node-set)
    7634           0 :         append_instruction(INST_GET_RESULT);
    7635           0 :         append_instruction(INST_POP_CONTEXT); // get rid of the node context
    7636             :     }
    7637           0 : }
    7638             : 
    7639             : 
    7640           0 : void variable_reference()
    7641             : {
    7642             :     // we arrive here with the '$' as the token
    7643           0 :     get_token();
    7644           0 :     if(f_last_token.f_token != token_t::tok_t::TOK_NCNAME)
    7645             :     {
    7646           0 :         throw QDomXPathException_SyntaxError("expected a variable name after the '$' sign");
    7647             :     }
    7648           0 :     token_t prefix(f_last_token);
    7649           0 :     get_token();
    7650           0 :     if(f_last_token.f_token == token_t::tok_t::TOK_COLON)
    7651             :     {
    7652           0 :         get_token();
    7653           0 :         if(f_last_token.f_token != token_t::tok_t::TOK_NCNAME)
    7654             :         {
    7655           0 :             throw QDomXPathException_SyntaxError(QString("expected a variable name after the prefix '%1:' sign").arg(prefix.f_string));
    7656             :         }
    7657             :         // concatenate the prefix within the name; not too sure why we'd
    7658             :         // have a prefix in the first place and we'd not likely to use
    7659             :         // variables at this point
    7660           0 :         prefix.f_string += ":" + f_last_token.f_string;
    7661             :     }
    7662           0 :     append_push_token(prefix);
    7663           0 :     append_instruction(INST_GET_VARIABLE);
    7664           0 : }
    7665             : 
    7666             : 
    7667           0 : void path_expr()
    7668             : {
    7669           0 :     switch(f_last_token.f_token)
    7670             :     {
    7671           0 :     case token_t::tok_t::TOK_OPEN_PARENTHESIS:
    7672             :         // we directly call OrExpr since:
    7673             :         //     Expr ::= OrExpr
    7674           0 :         or_expr();
    7675           0 :         if(f_last_token.f_token != token_t::tok_t::TOK_CLOSE_PARENTHESIS)
    7676             :         {
    7677           0 :             throw QDomXPathException_SyntaxError("expected a ')'");
    7678             :         }
    7679           0 :         break;
    7680             : 
    7681           0 :     case token_t::tok_t::TOK_INTEGER: // PathExpr => FilterExpr => PrimaryExpr
    7682             :     case token_t::tok_t::TOK_REAL: // PathExpr => FilterExpr => PrimaryExpr
    7683             :     case token_t::tok_t::TOK_STRING: // PathExpr => FilterExpr => PrimaryExpr
    7684           0 :         append_push_token(f_last_token);
    7685           0 :         get_token();
    7686           0 :         break;
    7687             : 
    7688           0 :     case token_t::tok_t::TOK_DOLLAR:
    7689           0 :         variable_reference();
    7690           0 :         break;
    7691             : 
    7692           0 :     case token_t::tok_t::TOK_SLASH: // PathExpr => LocationPath => AbsolutePath
    7693             :     case token_t::tok_t::TOK_DOUBLE_SLASH: // PathExpr => LocationPath => AbsolutePath
    7694             :     case token_t::tok_t::TOK_NCNAME: // PathExpr => PrimaryExpr => FunctionCall
    7695             :     case token_t::tok_t::TOK_AT: // PathExpr => LocationPath => RelativePath => Step => AxisSpecifier => AbbreviatedAxisSpecifier
    7696             :     case token_t::tok_t::TOK_DOT:
    7697             :     case token_t::tok_t::TOK_DOUBLE_DOT:
    7698           0 :         location_path();
    7699           0 :         break;
    7700             : 
    7701           0 :     case token_t::tok_t::TOK_PIPE:
    7702             :         // the '|' character is for the caller
    7703           0 :         return;
    7704             : 
    7705           0 :     default:
    7706           0 :         throw QDomXPathException_SyntaxError(QString("unexpected token \"%1\"").arg(f_last_token.f_string));
    7707             : 
    7708             :     }
    7709             : }
    7710             : 
    7711             : 
    7712             : /** \brief The UnionExpr is where it starts in XPath version 1.0
    7713             :  *
    7714             :  * At this point the UnionExpr is as defined in version 1.0 of XPath. In
    7715             :  * version 2.0 it changed and is a proper primary expression.
    7716             :  *
    7717             :  * The UnionExpr is quite peculiar at this point since if the path_expr
    7718             :  * does not return with a TOK_PIPE, then the union does not happen and
    7719             :  * the returned value has to be returned as is.
    7720             :  */
    7721           0 : void union_expr()
    7722             : {
    7723             :     // in case there is a pipe we'll need to have a duplicate of
    7724             :     // the input...
    7725             :     //append_instruction(INST_DUPLICATE1);
    7726             :     //++f_label_counter;
    7727             :     //QString variable(QString("$%1").arg(f_label_counter));
    7728             :     //append_push_string(variable);
    7729             :     //append_instruction(INST_SET_VARIABLE);
    7730             : 
    7731           0 :     path_expr();
    7732             : 
    7733           0 :     while(f_last_token.f_token == token_t::tok_t::TOK_PIPE)
    7734             :     {
    7735             :         // skip the pipe
    7736           0 :         get_token();
    7737             : 
    7738             :         //append_push_string(variable);
    7739             :         //append_instruction(INST_GET_VARIABLE);
    7740             : 
    7741           0 :         path_expr();
    7742           0 :         append_instruction(INST_MERGE_SETS);
    7743             :     }
    7744           0 : }
    7745             : 
    7746             : 
    7747           0 : void parse(bool show_commands)
    7748             : {
    7749           0 :     f_show_commands = show_commands;
    7750             : 
    7751           0 :     if(!get_token())
    7752             :     {
    7753           0 :         throw QDomXPathException_SyntaxError("calling parse() immediately generated an error");
    7754             :     }
    7755             :     //f_program.clear();
    7756           0 :     f_label_counter = 0;
    7757             : 
    7758             :     // save the input (we expect a node-set) in a variable
    7759           0 :     ++f_label_counter;
    7760           0 :     f_predicate_variable = QString("$%1").arg(f_label_counter);
    7761           0 :     append_push_string(f_predicate_variable);
    7762           0 :     append_instruction(INST_SET_VARIABLE);
    7763             : 
    7764           0 :     union_expr();
    7765             : 
    7766             :     // terminate the program with an INST_END instruction
    7767           0 :     append_instruction(INST_END);
    7768             : 
    7769           0 :     if(!f_future_labels.empty())
    7770             :     {
    7771           0 :         throw QDomXPathException_SyntaxError("some future labels never got defined");
    7772             :     }
    7773           0 : }
    7774             : 
    7775             : 
    7776           0 : QDomXPath::node_vector_t apply(QDomXPath::node_vector_t& nodes)
    7777             : {
    7778             :     // reset the states and functions
    7779           0 :     f_functions.clear();
    7780             : 
    7781             :     // setup the execution environment (program)
    7782           0 :     function_t function;
    7783           0 :     function.f_pc = f_program_start_offset;
    7784             : 
    7785             :     // set the node set on the stack
    7786           0 :     variant_t node_set;
    7787           0 :     node_set.setValue(nodes);
    7788           0 :     function.f_stack.push_back(node_set);
    7789             :     // one context to hold the result
    7790           0 :     context_t context;
    7791           0 :     function.f_contexts.push_back(context);
    7792             : 
    7793           0 :     f_functions.push_back(function);
    7794             : 
    7795             :     // execute the program
    7796             :     for(;;)
    7797             :     {
    7798           0 :         uint32_t const pc(f_functions.back().f_pc);
    7799           0 :         if(f_show_commands)
    7800             :         {
    7801           0 :             disassemble_instruction(pc);
    7802             :         }
    7803             : 
    7804           0 :         instruction_t const instruction(f_program[pc]);
    7805           0 :         if(instruction == INST_END)
    7806             :         {
    7807             :             // found the end of the program, return
    7808           0 :             break;
    7809             :         }
    7810           0 :         ++f_functions.back().f_pc;
    7811           0 :         (this->*g_instructions[instruction])();
    7812           0 :     }
    7813             : 
    7814             :     // we must have just one function on exit
    7815           0 :     if(f_functions.back().f_contexts.size() != 1)
    7816             :     {
    7817           0 :         throw QDomXPathException_InvalidError("function stack does not include just one item when existing program");
    7818             :     }
    7819             : 
    7820             :     // the first context we push must still be here, but only that one
    7821           0 :     if(f_functions.back().f_contexts.size() != 1)
    7822             :     {
    7823           0 :         throw QDomXPathException_InvalidError("context stack does not include just one item when existing program");
    7824             :     }
    7825             : 
    7826             :     // retrieve the result
    7827           0 :     if(f_functions.back().f_stack.size() != 1)
    7828             :     {
    7829           0 :         throw QDomXPathException_InvalidError("stack does not include just one item when existing program");
    7830             :     }
    7831           0 :     QDomXPath::node_vector_t result(f_functions.back().f_stack.back().getNodeSetValue());
    7832             : 
    7833             :     //context = f_functions.back().f_contexts.back();
    7834             :     //QDomXPath::node_vector_t result(context.f_result);
    7835             : 
    7836             :     // reset the states and functions
    7837             :     // (this won't happen on errors which is why we also do it on entry
    7838           0 :     f_functions.clear();
    7839             : 
    7840           0 :     return result;
    7841             : }
    7842             : 
    7843             : 
    7844             : #pragma GCC diagnostic push
    7845             : #pragma GCC diagnostic ignored "-Wunused-parameter"
    7846             : 
    7847           0 : uint32_t disassemble_undefined_instruction(uint32_t pc)
    7848             : {
    7849           0 :     std::cout << "***undefined instruction*** (" << f_program[pc - 1] << ")\n";
    7850           0 :     return 1;
    7851             : }
    7852             : 
    7853           0 : uint32_t disassemble_end(uint32_t pc)
    7854             : {
    7855           0 :     std::cout << "end\n";
    7856           0 :     return 1;
    7857             : }
    7858             : 
    7859           0 : uint32_t disassemble_call(uint32_t pc)
    7860             : {
    7861           0 :     std::cout << "call\n";
    7862           0 :     return 1;
    7863             : }
    7864             : 
    7865           0 : uint32_t disassemble_small_function(uint32_t pc)
    7866             : {
    7867           0 :     uint32_t size((f_program[pc + 0] << 8)
    7868           0 :                  | f_program[pc + 1]);
    7869           0 :     std::cout << "function (" << size << " bytes)\n";
    7870             :     // we do not skip the function here, we only print the header
    7871             :     // and the disassemble loop will print the contents
    7872             :     // TODO what's missing is a way to mark the end of the function!
    7873           0 :     return 3;
    7874             : }
    7875             : 
    7876           0 : uint32_t disassemble_large_function(uint32_t pc)
    7877             : {
    7878           0 :     uint32_t size((f_program[pc + 0] << 24)
    7879           0 :                 | (f_program[pc + 1] << 16)
    7880           0 :                 | (f_program[pc + 2] << 8)
    7881           0 :                 |  f_program[pc + 3]);
    7882           0 :     std::cout << "function (" << size << " bytes)\n";
    7883             :     // we do not skip the function here, we only print the header
    7884             :     // and the disassemble loop will print the contents
    7885             :     // TODO what's missing is a way to mark the end of the function!
    7886           0 :     return 5;
    7887             : }
    7888             : 
    7889           0 : uint32_t disassemble_jump(uint32_t pc)
    7890             : {
    7891           0 :     std::cout << "jump\n";
    7892           0 :     return 1;
    7893             : }
    7894             : 
    7895           0 : uint32_t disassemble_jump_if_true(uint32_t pc)
    7896             : {
    7897           0 :     std::cout << "jump_if_true\n";
    7898           0 :     return 1;
    7899             : }
    7900             : 
    7901           0 : uint32_t disassemble_jump_if_false(uint32_t pc)
    7902             : {
    7903           0 :     std::cout << "jump_if_false\n";
    7904           0 :     return 1;
    7905             : }
    7906             : 
    7907           0 : uint32_t disassemble_jump_if_zero(uint32_t pc)
    7908             : {
    7909           0 :     std::cout << "jump_if_zero\n";
    7910           0 :     return 1;
    7911             : }
    7912             : 
    7913           0 : uint32_t disassemble_return(uint32_t pc)
    7914             : {
    7915           0 :     std::cout << "return\n";
    7916           0 :     return 1;
    7917             : }
    7918             : 
    7919           0 : uint32_t disassemble_get_variable(uint32_t pc)
    7920             : {
    7921           0 :     std::cout << "get_variable\n";
    7922           0 :     return 1;
    7923             : }
    7924             : 
    7925           0 : uint32_t disassemble_set_variable(uint32_t pc)
    7926             : {
    7927           0 :     std::cout << "set_variable\n";
    7928           0 :     return 1;
    7929             : }
    7930             : 
    7931           0 : uint32_t disassemble_pop1(uint32_t pc)
    7932             : {
    7933           0 :     std::cout << "pop 1\n";
    7934           0 :     return 1;
    7935             : }
    7936             : 
    7937           0 : uint32_t disassemble_pop2(uint32_t pc)
    7938             : {
    7939           0 :     std::cout << "pop 2\n";
    7940           0 :     return 1;
    7941             : }
    7942             : 
    7943           0 : uint32_t disassemble_pop3(uint32_t pc)
    7944             : {
    7945           0 :     std::cout << "pop 3\n";
    7946           0 :     return 1;
    7947             : }
    7948             : 
    7949           0 : uint32_t disassemble_pop4(uint32_t pc)
    7950             : {
    7951           0 :     std::cout << "pop 4\n";
    7952           0 :     return 1;
    7953             : }
    7954             : 
    7955           0 : uint32_t disassemble_pop5(uint32_t pc)
    7956             : {
    7957           0 :     std::cout << "pop 5\n";
    7958           0 :     return 1;
    7959             : }
    7960             : 
    7961           0 : uint32_t disassemble_duplicate1(uint32_t pc)
    7962             : {
    7963           0 :     std::cout << "duplicate 1\n";
    7964           0 :     return 1;
    7965             : }
    7966             : 
    7967           0 : uint32_t disassemble_duplicate2(uint32_t pc)
    7968             : {
    7969           0 :     std::cout << "duplicate 2\n";
    7970           0 :     return 1;
    7971             : }
    7972             : 
    7973           0 : uint32_t disassemble_duplicate3(uint32_t pc)
    7974             : {
    7975           0 :     std::cout << "duplicate 3\n";
    7976           0 :     return 1;
    7977             : }
    7978             : 
    7979           0 : uint32_t disassemble_duplicate4(uint32_t pc)
    7980             : {
    7981           0 :     std::cout << "duplicate 4\n";
    7982           0 :     return 1;
    7983             : }
    7984             : 
    7985           0 : uint32_t disassemble_duplicate5(uint32_t pc)
    7986             : {
    7987           0 :     std::cout << "duplicate 5\n";
    7988           0 :     return 1;
    7989             : }
    7990             : 
    7991           0 : uint32_t disassemble_swap1(uint32_t pc)
    7992             : {
    7993           0 :     std::cout << "swap 1, 2\n";
    7994           0 :     return 1;
    7995             : }
    7996             : 
    7997           0 : uint32_t disassemble_swap2(uint32_t pc)
    7998             : {
    7999           0 :     std::cout << "swap 1, 3\n";
    8000           0 :     return 1;
    8001             : }
    8002             : 
    8003           0 : uint32_t disassemble_swap3(uint32_t pc)
    8004             : {
    8005           0 :     std::cout << "swap 1, 4\n";
    8006           0 :     return 1;
    8007             : }
    8008             : 
    8009           0 : uint32_t disassemble_swap4(uint32_t pc)
    8010             : {
    8011           0 :     std::cout << "swap 1, 5\n";
    8012           0 :     return 1;
    8013             : }
    8014             : 
    8015           0 : uint32_t disassemble_swap5(uint32_t pc)
    8016             : {
    8017           0 :     std::cout << "swap 1, 6\n";
    8018           0 :     return 1;
    8019             : }
    8020             : 
    8021           0 : uint32_t disassemble_swap2_3(uint32_t pc)
    8022             : {
    8023           0 :     std::cout << "swap 2, 3\n";
    8024           0 :     return 1;
    8025             : }
    8026             : 
    8027           0 : uint32_t disassemble_push_any_string(uint32_t pc)
    8028             : {
    8029           0 :     std::cout << "push_string \"*\"\n";
    8030           0 :     return 1;
    8031             : }
    8032             : 
    8033           0 : uint32_t disassemble_push_byte(uint32_t pc)
    8034             : {
    8035           0 :     int64_t value(static_cast<int64_t>(f_program[pc]));
    8036           0 :     std::cout << "push_integer " << value << std::endl;
    8037           0 :     return 2;
    8038             : }
    8039             : 
    8040           0 : uint32_t disassemble_push_double(uint32_t pc)
    8041             : {
    8042             :     union
    8043             :     {
    8044             :         uint64_t    f_int;
    8045             :         double      f_dbl;
    8046             :     } convert;
    8047           0 :     convert.f_int = (static_cast<int64_t>(f_program[pc + 0]) << 56)
    8048           0 :                   | (static_cast<int64_t>(f_program[pc + 1]) << 48)
    8049           0 :                   | (static_cast<int64_t>(f_program[pc + 2]) << 40)
    8050           0 :                   | (static_cast<int64_t>(f_program[pc + 3]) << 32)
    8051           0 :                   | (static_cast<int64_t>(f_program[pc + 4]) << 24)
    8052           0 :                   | (static_cast<int64_t>(f_program[pc + 5]) << 16)
    8053           0 :                   | (static_cast<int64_t>(f_program[pc + 6]) <<  8)
    8054           0 :                   |  static_cast<int64_t>(f_program[pc + 7]);
    8055           0 :     std::cout << "push_double " << convert.f_dbl << std::endl;
    8056           0 :     return 9;
    8057             : }
    8058             : 
    8059           0 : uint32_t disassemble_push_double_zero(uint32_t pc)
    8060             : {
    8061           0 :     std::cout << "push_double_zero\n";
    8062           0 :     return 1;
    8063             : }
    8064             : 
    8065           0 : uint32_t disassemble_push_empty_node_set(uint32_t pc)
    8066             : {
    8067           0 :     std::cout << "push_empty_node_set\n";
    8068           0 :     return 1;
    8069             : }
    8070             : 
    8071           0 : uint32_t disassemble_push_empty_set(uint32_t pc)
    8072             : {
    8073           0 :     std::cout << "push_empty_set\n";
    8074           0 :     return 1;
    8075             : }
    8076             : 
    8077           0 : uint32_t disassemble_push_empty_string(uint32_t pc)
    8078             : {
    8079           0 :     std::cout << "push_string \"\"\n";
    8080           0 :     return 1;
    8081             : }
    8082             : 
    8083           0 : uint32_t disassemble_push_end_of_arguments(uint32_t pc)
    8084             : {
    8085           0 :     std::cout << "push_end_of_arguments\n";
    8086           0 :     return 1;
    8087             : }
    8088             : 
    8089           0 : uint32_t disassemble_push_false(uint32_t pc)
    8090             : {
    8091           0 :     std::cout << "push_false\n";
    8092           0 :     return 1;
    8093             : }
    8094             : 
    8095           0 : uint32_t disassemble_push_large_string(uint32_t pc)
    8096             : {
    8097           0 :     uint32_t size = (static_cast<uint32_t>(f_program[pc + 0]) << 24)
    8098           0 :                   | (static_cast<uint32_t>(f_program[pc + 1]) << 16)
    8099           0 :                   | (static_cast<uint32_t>(f_program[pc + 2]) <<  8)
    8100           0 :                   |  static_cast<uint32_t>(f_program[pc + 3]);
    8101           0 :     std::string str(reinterpret_cast<char *>(&f_program[pc + 4]), size);
    8102           0 :     std::cout << "push_string \"" << str << "\"" << std::endl;
    8103           0 :     return 5 + size;
    8104             : }
    8105             : 
    8106           0 : uint32_t disassemble_push_long(uint32_t pc)
    8107             : {
    8108           0 :     int64_t value = (static_cast<int64_t>(f_program[pc + 0]) << 24)
    8109           0 :                   | (static_cast<int64_t>(f_program[pc + 1]) << 16)
    8110           0 :                   | (static_cast<int64_t>(f_program[pc + 2]) <<  8)
    8111           0 :                   |  static_cast<int64_t>(f_program[pc + 3]);
    8112           0 :     std::cout << "push_integer " << value << std::endl;
    8113           0 :     return 5;
    8114             : }
    8115             : 
    8116           0 : uint32_t disassemble_push_longlong(uint32_t pc)
    8117             : {
    8118           0 :     int64_t value = (static_cast<int64_t>(f_program[pc + 0]) << 56)
    8119           0 :                   | (static_cast<int64_t>(f_program[pc + 1]) << 48)
    8120           0 :                   | (static_cast<int64_t>(f_program[pc + 2]) << 40)
    8121           0 :                   | (static_cast<int64_t>(f_program[pc + 3]) << 32)
    8122           0 :                   | (static_cast<int64_t>(f_program[pc + 4]) << 24)
    8123           0 :                   | (static_cast<int64_t>(f_program[pc + 5]) << 16)
    8124           0 :                   | (static_cast<int64_t>(f_program[pc + 6]) <<  8)
    8125           0 :                   |  static_cast<int64_t>(f_program[pc + 7]);
    8126           0 :     std::cout << "push_integer " << value << std::endl;
    8127           0 :     return 9;
    8128             : }
    8129             : 
    8130           0 : uint32_t disassemble_push_medium_string(uint32_t pc)
    8131             : {
    8132           0 :     uint32_t size = (static_cast<uint32_t>(f_program[pc + 0]) << 8)
    8133           0 :                   |  static_cast<uint32_t>(f_program[pc + 1]);
    8134           0 :     std::string str(reinterpret_cast<char *>(&f_program[pc + 2]), size);
    8135           0 :     std::cout << "push_string \"" << str << "\"\n";
    8136           0 :     return 3 + size;
    8137             : }
    8138             : 
    8139           0 : uint32_t disassemble_push_negative_byte(uint32_t pc)
    8140             : {
    8141           0 :     int64_t value(static_cast<int64_t>(f_program[pc]) | 0xFFFFFFFFFFFFFF00LL);
    8142           0 :     std::cout << "push_integer " << value << std::endl;
    8143           0 :     return 2;
    8144             : }
    8145             : 
    8146           0 : uint32_t disassemble_push_negative_short(uint32_t pc)
    8147             : {
    8148           0 :     int64_t value((static_cast<int64_t>(f_program[pc]) << 8)
    8149           0 :                  | static_cast<int64_t>(f_program[pc])
    8150           0 :                  | 0xFFFFFFFFFFFF0000LL);
    8151           0 :     std::cout << "push_integer " << value << std::endl;
    8152           0 :     return 3;
    8153             : }
    8154             : 
    8155           0 : uint32_t disassemble_push_negative_long(uint32_t pc)
    8156             : {
    8157           0 :     int64_t value((static_cast<int64_t>(f_program[pc]) << 24)
    8158           0 :                 | (static_cast<int64_t>(f_program[pc]) << 16)
    8159           0 :                 | (static_cast<int64_t>(f_program[pc]) << 8)
    8160           0 :                 |  static_cast<int64_t>(f_program[pc])
    8161           0 :                 |  0xFFFFFFFF00000000LL);
    8162           0 :     std::cout << "push_integer " << value << std::endl;
    8163           0 :     return 5;
    8164             : }
    8165             : 
    8166           0 : uint32_t disassemble_push_short(uint32_t pc)
    8167             : {
    8168           0 :     int64_t value = (static_cast<int64_t>(f_program[pc + 0]) << 8)
    8169           0 :                   |  static_cast<int64_t>(f_program[pc + 1]);
    8170           0 :     std::cout << "push_integer " << value << std::endl;
    8171           0 :     return 5;
    8172             : }
    8173             : 
    8174           0 : uint32_t disassemble_push_small_string(uint32_t pc)
    8175             : {
    8176           0 :     uint32_t size = static_cast<uint32_t>(f_program[pc + 0]);
    8177           0 :     std::string str(reinterpret_cast<char *>(&f_program[pc + 1]), size);
    8178           0 :     std::cout << "push_string \"" << str << "\"\n";
    8179           0 :     return 2 + size;
    8180             : }
    8181             : 
    8182           0 : uint32_t disassemble_push_true(uint32_t pc)
    8183             : {
    8184           0 :     std::cout << "push_true\n";
    8185           0 :     return 1;
    8186             : }
    8187             : 
    8188           0 : uint32_t disassemble_push_zero(uint32_t pc)
    8189             : {
    8190           0 :     std::cout << "push_integer 0\n";
    8191           0 :     return 1;
    8192             : }
    8193             : 
    8194           0 : uint32_t disassemble_add(uint32_t pc)
    8195             : {
    8196           0 :     std::cout << "add\n";
    8197           0 :     return 1;
    8198             : }
    8199             : 
    8200           0 : uint32_t disassemble_and(uint32_t pc)
    8201             : {
    8202           0 :     std::cout << "and\n";
    8203           0 :     return 1;
    8204             : }
    8205             : 
    8206           0 : uint32_t disassemble_ceiling(uint32_t pc)
    8207             : {
    8208           0 :     std::cout << "ceiling\n";
    8209           0 :     return 1;
    8210             : }
    8211             : 
    8212           0 : uint32_t disassemble_decrement(uint32_t pc)
    8213             : {
    8214           0 :     std::cout << "decrement\n";
    8215           0 :     return 1;
    8216             : }
    8217             : 
    8218           0 : uint32_t disassemble_divide(uint32_t pc)
    8219             : {
    8220           0 :     std::cout << "divide\n";
    8221           0 :     return 1;
    8222             : }
    8223             : 
    8224           0 : uint32_t disassemble_equal(uint32_t pc)
    8225             : {
    8226           0 :     std::cout << "equal\n";
    8227           0 :     return 1;
    8228             : }
    8229             : 
    8230           0 : uint32_t disassemble_floor(uint32_t pc)
    8231             : {
    8232           0 :     std::cout << "floor\n";
    8233           0 :     return 1;
    8234             : }
    8235             : 
    8236           0 : uint32_t disassemble_greater_or_equal(uint32_t pc)
    8237             : {
    8238           0 :     std::cout << "greater_or_equal\n";
    8239           0 :     return 1;
    8240             : }
    8241             : 
    8242           0 : uint32_t disassemble_greater_than(uint32_t pc)
    8243             : {
    8244           0 :     std::cout << "greater_than\n";
    8245           0 :     return 1;
    8246             : }
    8247             : 
    8248           0 : uint32_t disassemble_idivide(uint32_t pc)
    8249             : {
    8250           0 :     std::cout << "idivide\n";
    8251           0 :     return 1;
    8252             : }
    8253             : 
    8254           0 : uint32_t disassemble_increment(uint32_t pc)
    8255             : {
    8256           0 :     std::cout << "increment\n";
    8257           0 :     return 1;
    8258             : }
    8259             : 
    8260           0 : uint32_t disassemble_less_or_equal(uint32_t pc)
    8261             : {
    8262           0 :     std::cout << "less_or_equal\n";
    8263           0 :     return 1;
    8264             : }
    8265             : 
    8266           0 : uint32_t disassemble_less_than(uint32_t pc)
    8267             : {
    8268           0 :     std::cout << "less_than\n";
    8269           0 :     return 1;
    8270             : }
    8271             : 
    8272           0 : uint32_t disassemble_modulo(uint32_t pc)
    8273             : {
    8274           0 :     std::cout << "modulo\n";
    8275           0 :     return 1;
    8276             : }
    8277             : 
    8278           0 : uint32_t disassemble_multiply(uint32_t pc)
    8279             : {
    8280           0 :     std::cout << "multiply\n";
    8281           0 :     return 1;
    8282             : }
    8283             : 
    8284           0 : uint32_t disassemble_negate(uint32_t pc)
    8285             : {
    8286           0 :     std::cout << "negate\n";
    8287           0 :     return 1;
    8288             : }
    8289             : 
    8290           0 : uint32_t disassemble_not(uint32_t pc)
    8291             : {
    8292           0 :     std::cout << "not\n";
    8293           0 :     return 1;
    8294             : }
    8295             : 
    8296           0 : uint32_t disassemble_not_equal(uint32_t pc)
    8297             : {
    8298           0 :     std::cout << "not_equal\n";
    8299           0 :     return 1;
    8300             : }
    8301             : 
    8302           0 : uint32_t disassemble_or(uint32_t pc)
    8303             : {
    8304           0 :     std::cout << "or\n";
    8305           0 :     return 1;
    8306             : }
    8307             : 
    8308           0 : uint32_t disassemble_round(uint32_t pc)
    8309             : {
    8310           0 :     std::cout << "round\n";
    8311           0 :     return 1;
    8312             : }
    8313             : 
    8314           0 : uint32_t disassemble_string_length(uint32_t pc)
    8315             : {
    8316           0 :     std::cout << "string_length\n";
    8317           0 :     return 1;
    8318             : }
    8319             : 
    8320           0 : uint32_t disassemble_subtract(uint32_t pc)
    8321             : {
    8322           0 :     std::cout << "subtract\n";
    8323           0 :     return 1;
    8324             : }
    8325             : 
    8326           0 : uint32_t disassemble_axis(uint32_t pc)
    8327             : {
    8328           0 :     std::cout << "axis\n";
    8329           0 :     return 1;
    8330             : }
    8331             : 
    8332           0 : uint32_t disassemble_root(uint32_t pc)
    8333             : {
    8334           0 :     std::cout << "root\n";
    8335           0 :     return 1;
    8336             : }
    8337             : 
    8338           0 : uint32_t disassemble_get_node_set(uint32_t pc)
    8339             : {
    8340           0 :     std::cout << "get_node_set\n";
    8341           0 :     return 1;
    8342             : }
    8343             : 
    8344           0 : uint32_t disassemble_set_node_set(uint32_t pc)
    8345             : {
    8346           0 :     std::cout << "set_node_set\n";
    8347           0 :     return 1;
    8348             : }
    8349             : 
    8350           0 : uint32_t disassemble_get_result(uint32_t pc)
    8351             : {
    8352           0 :     std::cout << "get_result\n";
    8353           0 :     return 1;
    8354             : }
    8355             : 
    8356           0 : uint32_t disassemble_set_result(uint32_t pc)
    8357             : {
    8358           0 :     std::cout << "set_result\n";
    8359           0 :     return 1;
    8360             : }
    8361             : 
    8362           0 : uint32_t disassemble_get_position(uint32_t pc)
    8363             : {
    8364           0 :     std::cout << "get_position\n";
    8365           0 :     return 1;
    8366             : }
    8367             : 
    8368           0 : uint32_t disassemble_set_position(uint32_t pc)
    8369             : {
    8370           0 :     std::cout << "set_position\n";
    8371           0 :     return 1;
    8372             : }
    8373             : 
    8374           0 : uint32_t disassemble_node_set_size(uint32_t pc)
    8375             : {
    8376           0 :     std::cout << "node_set_size\n";
    8377           0 :     return 1;
    8378             : }
    8379             : 
    8380           0 : uint32_t disassemble_merge_sets(uint32_t pc)
    8381             : {
    8382           0 :     std::cout << "merge_sets\n";
    8383           0 :     return 1;
    8384             : }
    8385             : 
    8386           0 : uint32_t disassemble_predicate(uint32_t pc)
    8387             : {
    8388           0 :     std::cout << "predicate\n";
    8389           0 :     return 1;
    8390             : }
    8391             : 
    8392           0 : uint32_t disassemble_create_node_context(uint32_t pc)
    8393             : {
    8394           0 :     std::cout << "create_node_context\n";
    8395           0 :     return 1;
    8396             : }
    8397             : 
    8398           0 : uint32_t disassemble_get_context_node(uint32_t pc)
    8399             : {
    8400           0 :     std::cout << "get_context_node\n";
    8401           0 :     return 1;
    8402             : }
    8403             : 
    8404           0 : uint32_t disassemble_next_context_node(uint32_t pc)
    8405             : {
    8406           0 :     std::cout << "next_context_node\n";
    8407           0 :     return 1;
    8408             : }
    8409             : 
    8410           0 : uint32_t disassemble_pop_context(uint32_t pc)
    8411             : {
    8412           0 :     std::cout << "pop_context\n";
    8413           0 :     return 1;
    8414             : }
    8415             : #pragma GCC diagnostic pop
    8416             : 
    8417             : 
    8418             : 
    8419           0 : int disassemble_instruction(int const pc)
    8420             : {
    8421             :     // a small indentation
    8422           0 :     std::ostream out(std::cout.rdbuf()); // copy so we don't mess up the manipulator in std::cout
    8423           0 :     out << std::setw(6) << pc << "- ";
    8424           0 :     instruction_t const inst(f_program[pc]);
    8425           0 :     return (this->*g_disassemble_instructions[inst])(pc + 1);
    8426             : }
    8427             : 
    8428             : 
    8429           0 : void disassemble()
    8430             : {
    8431           0 :     int pc(f_program_start_offset);
    8432           0 :     while(pc < f_program.size())
    8433             :     {
    8434           0 :         pc += disassemble_instruction(pc);
    8435             :     }
    8436           0 : }
    8437             : 
    8438             : 
    8439           0 : QString setProgram(const QDomXPath::program_t& program, bool show_commands)
    8440             : {
    8441           0 :     if(program[0] != QDomXPath::MAGIC[0]
    8442           0 :     || program[1] != QDomXPath::MAGIC[1]
    8443           0 :     || program[2] != QDomXPath::MAGIC[2]
    8444           0 :     || program[3] != QDomXPath::MAGIC[3])
    8445             :     {
    8446           0 :         throw QDomXPathException_InvalidMagic("this program does not start with the correct magic code");
    8447             :     }
    8448           0 :     if(program[4] != QDomXPath::VERSION_MAJOR
    8449           0 :     || program[5] != QDomXPath::VERSION_MINOR)
    8450             :     {
    8451             :         // we need a better test as we have newer versions, at this time,
    8452             :         // we do not need much more than what is here
    8453           0 :         throw QDomXPathException_InvalidMagic("this program version is not compatible");
    8454             :     }
    8455             : 
    8456           0 :     f_show_commands = show_commands;
    8457             : 
    8458           0 :     const int size((program[6] << 8) | program[7]);
    8459           0 :     f_program_start_offset = size + 8;
    8460           0 :     f_xpath = QString::fromUtf8(reinterpret_cast<const char *>(&program[8]), size);
    8461             : 
    8462           0 :     f_program = program;
    8463             : 
    8464           0 :     return f_xpath;
    8465             : }
    8466             : 
    8467             : 
    8468           0 : const QDomXPath::program_t& getProgram() const
    8469             : {
    8470           0 :     return f_program;
    8471             : }
    8472             : 
    8473             : 
    8474             : private:
    8475             :     QDomXPath *                 f_owner = nullptr;
    8476             :     bool                        f_show_commands = false;
    8477             : 
    8478             :     // parser parameters
    8479             :     QString                     f_xpath = QString();
    8480             :     const QChar *               f_start = nullptr;
    8481             :     const QChar *               f_in = nullptr;
    8482             :     token_t                     f_unget_token = token_t();
    8483             :     token_t                     f_last_token = token_t();
    8484             :     uint32_t                    f_label_counter = 0;
    8485             :     label_offsets_t             f_labels = label_offsets_t();
    8486             :     future_labels_t             f_future_labels = future_labels_t();
    8487             :     QString                     f_end_label = QString();
    8488             :     QString                     f_predicate_variable = QString();
    8489             : 
    8490             :     // execution environment
    8491             :     //QDomXPath::node_vector_t    f_result;
    8492             :     int32_t                     f_program_start_offset = -1;
    8493             :     QDomXPath::program_t        f_program = QDomXPath::program_t();
    8494             :     function_vector_t           f_functions = function_vector_t();
    8495             : };
    8496             : 
    8497             : 
    8498             : QDomXPath::QDomXPathImpl::instruction_function_t const QDomXPath::QDomXPathImpl::g_instructions[256] =
    8499             : {
    8500             :       /* 0x00 */ &QDomXPathImpl::inst_end
    8501             :     , /* 0x01 */ &QDomXPathImpl::inst_call
    8502             :     , /* 0x02 */ &QDomXPathImpl::inst_small_function
    8503             :     , /* 0x03 */ &QDomXPathImpl::inst_large_function
    8504             :     , /* 0x04 */ &QDomXPathImpl::inst_jump
    8505             :     , /* 0x05 */ &QDomXPathImpl::inst_jump_if_true
    8506             :     , /* 0x06 */ &QDomXPathImpl::inst_jump_if_false
    8507             :     , /* 0x07 */ &QDomXPathImpl::inst_jump_if_zero
    8508             :     , /* 0x08 */ &QDomXPathImpl::inst_return
    8509             :     , /* 0x09 */ &QDomXPathImpl::inst_undefined_instruction
    8510             :     , /* 0x0A */ &QDomXPathImpl::inst_undefined_instruction
    8511             :     , /* 0x0B */ &QDomXPathImpl::inst_undefined_instruction
    8512             :     , /* 0x0C */ &QDomXPathImpl::inst_undefined_instruction
    8513             :     , /* 0x0D */ &QDomXPathImpl::inst_undefined_instruction
    8514             :     , /* 0x0E */ &QDomXPathImpl::inst_undefined_instruction
    8515             :     , /* 0x0F */ &QDomXPathImpl::inst_undefined_instruction
    8516             : 
    8517             :     , /* 0x10 */ &QDomXPathImpl::inst_get_variable
    8518             :     , /* 0x11 */ &QDomXPathImpl::inst_set_variable
    8519             :     , /* 0x12 */ &QDomXPathImpl::inst_undefined_instruction
    8520             :     , /* 0x13 */ &QDomXPathImpl::inst_undefined_instruction
    8521             :     , /* 0x14 */ &QDomXPathImpl::inst_undefined_instruction
    8522             :     , /* 0x15 */ &QDomXPathImpl::inst_undefined_instruction
    8523             :     , /* 0x16 */ &QDomXPathImpl::inst_undefined_instruction
    8524             :     , /* 0x17 */ &QDomXPathImpl::inst_undefined_instruction
    8525             :     , /* 0x18 */ &QDomXPathImpl::inst_undefined_instruction
    8526             :     , /* 0x19 */ &QDomXPathImpl::inst_undefined_instruction
    8527             :     , /* 0x1A */ &QDomXPathImpl::inst_undefined_instruction
    8528             :     , /* 0x1B */ &QDomXPathImpl::inst_undefined_instruction
    8529             :     , /* 0x1C */ &QDomXPathImpl::inst_undefined_instruction
    8530             :     , /* 0x1D */ &QDomXPathImpl::inst_undefined_instruction
    8531             :     , /* 0x1E */ &QDomXPathImpl::inst_undefined_instruction
    8532             :     , /* 0x1F */ &QDomXPathImpl::inst_undefined_instruction
    8533             : 
    8534             :     , /* 0x20 */ &QDomXPathImpl::inst_pop1
    8535             :     , /* 0x21 */ &QDomXPathImpl::inst_pop2
    8536             :     , /* 0x22 */ &QDomXPathImpl::inst_pop3
    8537             :     , /* 0x23 */ &QDomXPathImpl::inst_pop4
    8538             :     , /* 0x24 */ &QDomXPathImpl::inst_pop5
    8539             :     , /* 0x25 */ &QDomXPathImpl::inst_undefined_instruction
    8540             :     , /* 0x26 */ &QDomXPathImpl::inst_undefined_instruction
    8541             :     , /* 0x27 */ &QDomXPathImpl::inst_undefined_instruction
    8542             :     , /* 0x28 */ &QDomXPathImpl::inst_undefined_instruction
    8543             :     , /* 0x29 */ &QDomXPathImpl::inst_undefined_instruction
    8544             :     , /* 0x2A */ &QDomXPathImpl::inst_duplicate1
    8545             :     , /* 0x2B */ &QDomXPathImpl::inst_duplicate2
    8546             :     , /* 0x2C */ &QDomXPathImpl::inst_duplicate3
    8547             :     , /* 0x2D */ &QDomXPathImpl::inst_duplicate4
    8548             :     , /* 0x2E */ &QDomXPathImpl::inst_duplicate5
    8549             :     , /* 0x2F */ &QDomXPathImpl::inst_undefined_instruction
    8550             : 
    8551             :     , /* 0x30 */ &QDomXPathImpl::inst_swap1
    8552             :     , /* 0x31 */ &QDomXPathImpl::inst_swap2
    8553             :     , /* 0x32 */ &QDomXPathImpl::inst_swap3
    8554             :     , /* 0x33 */ &QDomXPathImpl::inst_swap4
    8555             :     , /* 0x34 */ &QDomXPathImpl::inst_swap5
    8556             :     , /* 0x35 */ &QDomXPathImpl::inst_swap2_3
    8557             :     , /* 0x36 */ &QDomXPathImpl::inst_undefined_instruction
    8558             :     , /* 0x37 */ &QDomXPathImpl::inst_undefined_instruction
    8559             :     , /* 0x38 */ &QDomXPathImpl::inst_undefined_instruction
    8560             :     , /* 0x39 */ &QDomXPathImpl::inst_undefined_instruction
    8561             :     , /* 0x3A */ &QDomXPathImpl::inst_undefined_instruction
    8562             :     , /* 0x3B */ &QDomXPathImpl::inst_undefined_instruction
    8563             :     , /* 0x3C */ &QDomXPathImpl::inst_undefined_instruction
    8564             :     , /* 0x3D */ &QDomXPathImpl::inst_undefined_instruction
    8565             :     , /* 0x3E */ &QDomXPathImpl::inst_undefined_instruction
    8566             :     , /* 0x3F */ &QDomXPathImpl::inst_undefined_instruction
    8567             : 
    8568             :     , /* 0x40 */ &QDomXPathImpl::inst_push_any_string
    8569             :     , /* 0x41 */ &QDomXPathImpl::inst_push_byte
    8570             :     , /* 0x42 */ &QDomXPathImpl::inst_push_double
    8571             :     , /* 0x43 */ &QDomXPathImpl::inst_push_double_zero
    8572             :     , /* 0x44 */ &QDomXPathImpl::inst_push_empty_node_set
    8573             :     , /* 0x45 */ &QDomXPathImpl::inst_push_empty_set
    8574             :     , /* 0x46 */ &QDomXPathImpl::inst_push_empty_string
    8575             :     , /* 0x47 */ &QDomXPathImpl::inst_push_end_of_arguments
    8576             :     , /* 0x48 */ &QDomXPathImpl::inst_push_false
    8577             :     , /* 0x49 */ &QDomXPathImpl::inst_push_large_string
    8578             :     , /* 0x4A */ &QDomXPathImpl::inst_push_long
    8579             :     , /* 0x4B */ &QDomXPathImpl::inst_push_longlong
    8580             :     , /* 0x4C */ &QDomXPathImpl::inst_push_medium_string
    8581             :     , /* 0x4D */ &QDomXPathImpl::inst_push_negative_byte
    8582             :     , /* 0x4E */ &QDomXPathImpl::inst_push_negative_short
    8583             :     , /* 0x4F */ &QDomXPathImpl::inst_push_negative_long
    8584             : 
    8585             :     , /* 0x50 */ &QDomXPathImpl::inst_push_short
    8586             :     , /* 0x51 */ &QDomXPathImpl::inst_push_small_string
    8587             :     , /* 0x52 */ &QDomXPathImpl::inst_push_true
    8588             :     , /* 0x53 */ &QDomXPathImpl::inst_push_zero
    8589             :     , /* 0x54 */ &QDomXPathImpl::inst_undefined_instruction
    8590             :     , /* 0x55 */ &QDomXPathImpl::inst_undefined_instruction
    8591             :     , /* 0x56 */ &QDomXPathImpl::inst_undefined_instruction
    8592             :     , /* 0x57 */ &QDomXPathImpl::inst_undefined_instruction
    8593             :     , /* 0x58 */ &QDomXPathImpl::inst_undefined_instruction
    8594             :     , /* 0x59 */ &QDomXPathImpl::inst_undefined_instruction
    8595             :     , /* 0x5A */ &QDomXPathImpl::inst_undefined_instruction
    8596             :     , /* 0x5B */ &QDomXPathImpl::inst_undefined_instruction
    8597             :     , /* 0x5C */ &QDomXPathImpl::inst_undefined_instruction
    8598             :     , /* 0x5D */ &QDomXPathImpl::inst_undefined_instruction
    8599             :     , /* 0x5E */ &QDomXPathImpl::inst_undefined_instruction
    8600             :     , /* 0x5F */ &QDomXPathImpl::inst_undefined_instruction
    8601             : 
    8602             :     , /* 0x60 */ &QDomXPathImpl::inst_add
    8603             :     , /* 0x61 */ &QDomXPathImpl::inst_and
    8604             :     , /* 0x62 */ &QDomXPathImpl::inst_ceiling
    8605             :     , /* 0x63 */ &QDomXPathImpl::inst_decrement
    8606             :     , /* 0x64 */ &QDomXPathImpl::inst_divide
    8607             :     , /* 0x65 */ &QDomXPathImpl::inst_equal
    8608             :     , /* 0x66 */ &QDomXPathImpl::inst_floor
    8609             :     , /* 0x67 */ &QDomXPathImpl::inst_greater_or_equal
    8610             :     , /* 0x68 */ &QDomXPathImpl::inst_greater_than
    8611             :     , /* 0x69 */ &QDomXPathImpl::inst_idivide
    8612             :     , /* 0x6A */ &QDomXPathImpl::inst_increment
    8613             :     , /* 0x6B */ &QDomXPathImpl::inst_less_or_equal
    8614             :     , /* 0x6C */ &QDomXPathImpl::inst_less_than
    8615             :     , /* 0x6D */ &QDomXPathImpl::inst_modulo
    8616             :     , /* 0x6E */ &QDomXPathImpl::inst_multiply
    8617             :     , /* 0x6F */ &QDomXPathImpl::inst_negate
    8618             : 
    8619             :     , /* 0x70 */ &QDomXPathImpl::inst_not
    8620             :     , /* 0x71 */ &QDomXPathImpl::inst_not_equal
    8621             :     , /* 0x72 */ &QDomXPathImpl::inst_or
    8622             :     , /* 0x73 */ &QDomXPathImpl::inst_round
    8623             :     , /* 0x74 */ &QDomXPathImpl::inst_string_length
    8624             :     , /* 0x75 */ &QDomXPathImpl::inst_subtract
    8625             :     , /* 0x76 */ &QDomXPathImpl::inst_undefined_instruction
    8626             :     , /* 0x77 */ &QDomXPathImpl::inst_undefined_instruction
    8627             :     , /* 0x78 */ &QDomXPathImpl::inst_undefined_instruction
    8628             :     , /* 0x79 */ &QDomXPathImpl::inst_undefined_instruction
    8629             :     , /* 0x7A */ &QDomXPathImpl::inst_undefined_instruction
    8630             :     , /* 0x7B */ &QDomXPathImpl::inst_undefined_instruction
    8631             :     , /* 0x7C */ &QDomXPathImpl::inst_undefined_instruction
    8632             :     , /* 0x7D */ &QDomXPathImpl::inst_undefined_instruction
    8633             :     , /* 0x7E */ &QDomXPathImpl::inst_undefined_instruction
    8634             :     , /* 0x7F */ &QDomXPathImpl::inst_undefined_instruction
    8635             : 
    8636             :     , /* 0x80 */ &QDomXPathImpl::inst_axis
    8637             :     , /* 0x81 */ &QDomXPathImpl::inst_root
    8638             :     , /* 0x82 */ &QDomXPathImpl::inst_get_node_set
    8639             :     , /* 0x83 */ &QDomXPathImpl::inst_set_node_set
    8640             :     , /* 0x84 */ &QDomXPathImpl::inst_get_result
    8641             :     , /* 0x85 */ &QDomXPathImpl::inst_set_result
    8642             :     , /* 0x86 */ &QDomXPathImpl::inst_get_position
    8643             :     , /* 0x87 */ &QDomXPathImpl::inst_set_position
    8644             :     , /* 0x88 */ &QDomXPathImpl::inst_node_set_size
    8645             :     , /* 0x89 */ &QDomXPathImpl::inst_merge_sets
    8646             :     , /* 0x8A */ &QDomXPathImpl::inst_predicate
    8647             :     , /* 0x8B */ &QDomXPathImpl::inst_create_node_context
    8648             :     , /* 0x8C */ &QDomXPathImpl::inst_get_context_node
    8649             :     , /* 0x8D */ &QDomXPathImpl::inst_next_context_node
    8650             :     , /* 0x8E */ &QDomXPathImpl::inst_pop_context
    8651             :     , /* 0x8F */ &QDomXPathImpl::inst_undefined_instruction
    8652             : 
    8653             :     , /* 0x90 */ &QDomXPathImpl::inst_undefined_instruction
    8654             :     , /* 0x91 */ &QDomXPathImpl::inst_undefined_instruction
    8655             :     , /* 0x92 */ &QDomXPathImpl::inst_undefined_instruction
    8656             :     , /* 0x93 */ &QDomXPathImpl::inst_undefined_instruction
    8657             :     , /* 0x94 */ &QDomXPathImpl::inst_undefined_instruction
    8658             :     , /* 0x95 */ &QDomXPathImpl::inst_undefined_instruction
    8659             :     , /* 0x96 */ &QDomXPathImpl::inst_undefined_instruction
    8660             :     , /* 0x97 */ &QDomXPathImpl::inst_undefined_instruction
    8661             :     , /* 0x98 */ &QDomXPathImpl::inst_undefined_instruction
    8662             :     , /* 0x99 */ &QDomXPathImpl::inst_undefined_instruction
    8663             :     , /* 0x9A */ &QDomXPathImpl::inst_undefined_instruction
    8664             :     , /* 0x9B */ &QDomXPathImpl::inst_undefined_instruction
    8665             :     , /* 0x9C */ &QDomXPathImpl::inst_undefined_instruction
    8666             :     , /* 0x9D */ &QDomXPathImpl::inst_undefined_instruction
    8667             :     , /* 0x9E */ &QDomXPathImpl::inst_undefined_instruction
    8668             :     , /* 0x9F */ &QDomXPathImpl::inst_undefined_instruction
    8669             : 
    8670             :     , /* 0xA0 */ &QDomXPathImpl::inst_undefined_instruction
    8671             :     , /* 0xA1 */ &QDomXPathImpl::inst_undefined_instruction
    8672             :     , /* 0xA2 */ &QDomXPathImpl::inst_undefined_instruction
    8673             :     , /* 0xA3 */ &QDomXPathImpl::inst_undefined_instruction
    8674             :     , /* 0xA4 */ &QDomXPathImpl::inst_undefined_instruction
    8675             :     , /* 0xA5 */ &QDomXPathImpl::inst_undefined_instruction
    8676             :     , /* 0xA6 */ &QDomXPathImpl::inst_undefined_instruction
    8677             :     , /* 0xA7 */ &QDomXPathImpl::inst_undefined_instruction
    8678             :     , /* 0xA8 */ &QDomXPathImpl::inst_undefined_instruction
    8679             :     , /* 0xA9 */ &QDomXPathImpl::inst_undefined_instruction
    8680             :     , /* 0xAA */ &QDomXPathImpl::inst_undefined_instruction
    8681             :     , /* 0xAB */ &QDomXPathImpl::inst_undefined_instruction
    8682             :     , /* 0xAC */ &QDomXPathImpl::inst_undefined_instruction
    8683             :     , /* 0xAD */ &QDomXPathImpl::inst_undefined_instruction
    8684             :     , /* 0xAE */ &QDomXPathImpl::inst_undefined_instruction
    8685             :     , /* 0xAF */ &QDomXPathImpl::inst_undefined_instruction
    8686             : 
    8687             :     , /* 0xB0 */ &QDomXPathImpl::inst_undefined_instruction
    8688             :     , /* 0xB1 */ &QDomXPathImpl::inst_undefined_instruction
    8689             :     , /* 0xB2 */ &QDomXPathImpl::inst_undefined_instruction
    8690             :     , /* 0xB3 */ &QDomXPathImpl::inst_undefined_instruction
    8691             :     , /* 0xB4 */ &QDomXPathImpl::inst_undefined_instruction
    8692             :     , /* 0xB5 */ &QDomXPathImpl::inst_undefined_instruction
    8693             :     , /* 0xB6 */ &QDomXPathImpl::inst_undefined_instruction
    8694             :     , /* 0xB7 */ &QDomXPathImpl::inst_undefined_instruction
    8695             :     , /* 0xB8 */ &QDomXPathImpl::inst_undefined_instruction
    8696             :     , /* 0xB9 */ &QDomXPathImpl::inst_undefined_instruction
    8697             :     , /* 0xBA */ &QDomXPathImpl::inst_undefined_instruction
    8698             :     , /* 0xBB */ &QDomXPathImpl::inst_undefined_instruction
    8699             :     , /* 0xBC */ &QDomXPathImpl::inst_undefined_instruction
    8700             :     , /* 0xBD */ &QDomXPathImpl::inst_undefined_instruction
    8701             :     , /* 0xBE */ &QDomXPathImpl::inst_undefined_instruction
    8702             :     , /* 0xBF */ &QDomXPathImpl::inst_undefined_instruction
    8703             : 
    8704             :     , /* 0xC0 */ &QDomXPathImpl::inst_undefined_instruction
    8705             :     , /* 0xC1 */ &QDomXPathImpl::inst_undefined_instruction
    8706             :     , /* 0xC2 */ &QDomXPathImpl::inst_undefined_instruction
    8707             :     , /* 0xC3 */ &QDomXPathImpl::inst_undefined_instruction
    8708             :     , /* 0xC4 */ &QDomXPathImpl::inst_undefined_instruction
    8709             :     , /* 0xC5 */ &QDomXPathImpl::inst_undefined_instruction
    8710             :     , /* 0xC6 */ &QDomXPathImpl::inst_undefined_instruction
    8711             :     , /* 0xC7 */ &QDomXPathImpl::inst_undefined_instruction
    8712             :     , /* 0xC8 */ &QDomXPathImpl::inst_undefined_instruction
    8713             :     , /* 0xC9 */ &QDomXPathImpl::inst_undefined_instruction
    8714             :     , /* 0xCA */ &QDomXPathImpl::inst_undefined_instruction
    8715             :     , /* 0xCB */ &QDomXPathImpl::inst_undefined_instruction
    8716             :     , /* 0xCC */ &QDomXPathImpl::inst_undefined_instruction
    8717             :     , /* 0xCD */ &QDomXPathImpl::inst_undefined_instruction
    8718             :     , /* 0xCE */ &QDomXPathImpl::inst_undefined_instruction
    8719             :     , /* 0xCF */ &QDomXPathImpl::inst_undefined_instruction
    8720             : 
    8721             :     , /* 0xD0 */ &QDomXPathImpl::inst_undefined_instruction
    8722             :     , /* 0xD1 */ &QDomXPathImpl::inst_undefined_instruction
    8723             :     , /* 0xD2 */ &QDomXPathImpl::inst_undefined_instruction
    8724             :     , /* 0xD3 */ &QDomXPathImpl::inst_undefined_instruction
    8725             :     , /* 0xD4 */ &QDomXPathImpl::inst_undefined_instruction
    8726             :     , /* 0xD5 */ &QDomXPathImpl::inst_undefined_instruction
    8727             :     , /* 0xD6 */ &QDomXPathImpl::inst_undefined_instruction
    8728             :     , /* 0xD7 */ &QDomXPathImpl::inst_undefined_instruction
    8729             :     , /* 0xD8 */ &QDomXPathImpl::inst_undefined_instruction
    8730             :     , /* 0xD9 */ &QDomXPathImpl::inst_undefined_instruction
    8731             :     , /* 0xDA */ &QDomXPathImpl::inst_undefined_instruction
    8732             :     , /* 0xDB */ &QDomXPathImpl::inst_undefined_instruction
    8733             :     , /* 0xDC */ &QDomXPathImpl::inst_undefined_instruction
    8734             :     , /* 0xDD */ &QDomXPathImpl::inst_undefined_instruction
    8735             :     , /* 0xDE */ &QDomXPathImpl::inst_undefined_instruction
    8736             :     , /* 0xDF */ &QDomXPathImpl::inst_undefined_instruction
    8737             : 
    8738             :     , /* 0xE0 */ &QDomXPathImpl::inst_undefined_instruction
    8739             :     , /* 0xE1 */ &QDomXPathImpl::inst_undefined_instruction
    8740             :     , /* 0xE2 */ &QDomXPathImpl::inst_undefined_instruction
    8741             :     , /* 0xE3 */ &QDomXPathImpl::inst_undefined_instruction
    8742             :     , /* 0xE4 */ &QDomXPathImpl::inst_undefined_instruction
    8743             :     , /* 0xE5 */ &QDomXPathImpl::inst_undefined_instruction
    8744             :     , /* 0xE6 */ &QDomXPathImpl::inst_undefined_instruction
    8745             :     , /* 0xE7 */ &QDomXPathImpl::inst_undefined_instruction
    8746             :     , /* 0xE8 */ &QDomXPathImpl::inst_undefined_instruction
    8747             :     , /* 0xE9 */ &QDomXPathImpl::inst_undefined_instruction
    8748             :     , /* 0xEA */ &QDomXPathImpl::inst_undefined_instruction
    8749             :     , /* 0xEB */ &QDomXPathImpl::inst_undefined_instruction
    8750             :     , /* 0xEC */ &QDomXPathImpl::inst_undefined_instruction
    8751             :     , /* 0xED */ &QDomXPathImpl::inst_undefined_instruction
    8752             :     , /* 0xEE */ &QDomXPathImpl::inst_undefined_instruction
    8753             :     , /* 0xEF */ &QDomXPathImpl::inst_undefined_instruction
    8754             : 
    8755             :     , /* 0xF0 */ &QDomXPathImpl::inst_undefined_instruction
    8756             :     , /* 0xF1 */ &QDomXPathImpl::inst_undefined_instruction
    8757             :     , /* 0xF2 */ &QDomXPathImpl::inst_undefined_instruction
    8758             :     , /* 0xF3 */ &QDomXPathImpl::inst_undefined_instruction
    8759             :     , /* 0xF4 */ &QDomXPathImpl::inst_undefined_instruction
    8760             :     , /* 0xF5 */ &QDomXPathImpl::inst_undefined_instruction
    8761             :     , /* 0xF6 */ &QDomXPathImpl::inst_undefined_instruction
    8762             :     , /* 0xF7 */ &QDomXPathImpl::inst_undefined_instruction
    8763             :     , /* 0xF8 */ &QDomXPathImpl::inst_undefined_instruction
    8764             :     , /* 0xF9 */ &QDomXPathImpl::inst_undefined_instruction
    8765             :     , /* 0xFA */ &QDomXPathImpl::inst_undefined_instruction
    8766             :     , /* 0xFB */ &QDomXPathImpl::inst_undefined_instruction
    8767             :     , /* 0xFC */ &QDomXPathImpl::inst_undefined_instruction
    8768             :     , /* 0xFD */ &QDomXPathImpl::inst_undefined_instruction
    8769             :     , /* 0xFE */ &QDomXPathImpl::inst_undefined_instruction
    8770             :     , /* 0xFF */ &QDomXPathImpl::inst_undefined_instruction
    8771             : };
    8772             : 
    8773             : 
    8774             : QDomXPath::QDomXPathImpl::disassembly_function_t const QDomXPath::QDomXPathImpl::g_disassemble_instructions[256] =
    8775             : {
    8776             :       /* 0x00 */ &QDomXPathImpl::disassemble_end
    8777             :     , /* 0x01 */ &QDomXPathImpl::disassemble_call
    8778             :     , /* 0x02 */ &QDomXPathImpl::disassemble_small_function
    8779             :     , /* 0x03 */ &QDomXPathImpl::disassemble_large_function
    8780             :     , /* 0x04 */ &QDomXPathImpl::disassemble_jump
    8781             :     , /* 0x05 */ &QDomXPathImpl::disassemble_jump_if_true
    8782             :     , /* 0x06 */ &QDomXPathImpl::disassemble_jump_if_false
    8783             :     , /* 0x07 */ &QDomXPathImpl::disassemble_jump_if_zero
    8784             :     , /* 0x08 */ &QDomXPathImpl::disassemble_return
    8785             :     , /* 0x09 */ &QDomXPathImpl::disassemble_undefined_instruction
    8786             :     , /* 0x0A */ &QDomXPathImpl::disassemble_undefined_instruction
    8787             :     , /* 0x0B */ &QDomXPathImpl::disassemble_undefined_instruction
    8788             :     , /* 0x0C */ &QDomXPathImpl::disassemble_undefined_instruction
    8789             :     , /* 0x0D */ &QDomXPathImpl::disassemble_undefined_instruction
    8790             :     , /* 0x0E */ &QDomXPathImpl::disassemble_undefined_instruction
    8791             :     , /* 0x0F */ &QDomXPathImpl::disassemble_undefined_instruction
    8792             : 
    8793             :     , /* 0x10 */ &QDomXPathImpl::disassemble_get_variable
    8794             :     , /* 0x11 */ &QDomXPathImpl::disassemble_set_variable
    8795             :     , /* 0x12 */ &QDomXPathImpl::disassemble_undefined_instruction
    8796             :     , /* 0x13 */ &QDomXPathImpl::disassemble_undefined_instruction
    8797             :     , /* 0x14 */ &QDomXPathImpl::disassemble_undefined_instruction
    8798             :     , /* 0x15 */ &QDomXPathImpl::disassemble_undefined_instruction
    8799             :     , /* 0x16 */ &QDomXPathImpl::disassemble_undefined_instruction
    8800             :     , /* 0x17 */ &QDomXPathImpl::disassemble_undefined_instruction
    8801             :     , /* 0x18 */ &QDomXPathImpl::disassemble_undefined_instruction
    8802             :     , /* 0x19 */ &QDomXPathImpl::disassemble_undefined_instruction
    8803             :     , /* 0x1A */ &QDomXPathImpl::disassemble_undefined_instruction
    8804             :     , /* 0x1B */ &QDomXPathImpl::disassemble_undefined_instruction
    8805             :     , /* 0x1C */ &QDomXPathImpl::disassemble_undefined_instruction
    8806             :     , /* 0x1D */ &QDomXPathImpl::disassemble_undefined_instruction
    8807             :     , /* 0x1E */ &QDomXPathImpl::disassemble_undefined_instruction
    8808             :     , /* 0x1F */ &QDomXPathImpl::disassemble_undefined_instruction
    8809             : 
    8810             :     , /* 0x20 */ &QDomXPathImpl::disassemble_pop1
    8811             :     , /* 0x21 */ &QDomXPathImpl::disassemble_pop2
    8812             :     , /* 0x22 */ &QDomXPathImpl::disassemble_pop3
    8813             :     , /* 0x23 */ &QDomXPathImpl::disassemble_pop4
    8814             :     , /* 0x24 */ &QDomXPathImpl::disassemble_pop5
    8815             :     , /* 0x25 */ &QDomXPathImpl::disassemble_undefined_instruction
    8816             :     , /* 0x26 */ &QDomXPathImpl::disassemble_undefined_instruction
    8817             :     , /* 0x27 */ &QDomXPathImpl::disassemble_undefined_instruction
    8818             :     , /* 0x28 */ &QDomXPathImpl::disassemble_undefined_instruction
    8819             :     , /* 0x29 */ &QDomXPathImpl::disassemble_undefined_instruction
    8820             :     , /* 0x2A */ &QDomXPathImpl::disassemble_duplicate1
    8821             :     , /* 0x2B */ &QDomXPathImpl::disassemble_duplicate2
    8822             :     , /* 0x2C */ &QDomXPathImpl::disassemble_duplicate3
    8823             :     , /* 0x2D */ &QDomXPathImpl::disassemble_duplicate4
    8824             :     , /* 0x2E */ &QDomXPathImpl::disassemble_duplicate5
    8825             :     , /* 0x2F */ &QDomXPathImpl::disassemble_undefined_instruction
    8826             : 
    8827             :     , /* 0x30 */ &QDomXPathImpl::disassemble_swap1
    8828             :     , /* 0x31 */ &QDomXPathImpl::disassemble_swap2
    8829             :     , /* 0x32 */ &QDomXPathImpl::disassemble_swap3
    8830             :     , /* 0x33 */ &QDomXPathImpl::disassemble_swap4
    8831             :     , /* 0x34 */ &QDomXPathImpl::disassemble_swap5
    8832             :     , /* 0x35 */ &QDomXPathImpl::disassemble_swap2_3
    8833             :     , /* 0x36 */ &QDomXPathImpl::disassemble_undefined_instruction
    8834             :     , /* 0x37 */ &QDomXPathImpl::disassemble_undefined_instruction
    8835             :     , /* 0x38 */ &QDomXPathImpl::disassemble_undefined_instruction
    8836             :     , /* 0x39 */ &QDomXPathImpl::disassemble_undefined_instruction
    8837             :     , /* 0x3A */ &QDomXPathImpl::disassemble_undefined_instruction
    8838             :     , /* 0x3B */ &QDomXPathImpl::disassemble_undefined_instruction
    8839             :     , /* 0x3C */ &QDomXPathImpl::disassemble_undefined_instruction
    8840             :     , /* 0x3D */ &QDomXPathImpl::disassemble_undefined_instruction
    8841             :     , /* 0x3E */ &QDomXPathImpl::disassemble_undefined_instruction
    8842             :     , /* 0x3F */ &QDomXPathImpl::disassemble_undefined_instruction
    8843             : 
    8844             :     , /* 0x40 */ &QDomXPathImpl::disassemble_push_any_string
    8845             :     , /* 0x41 */ &QDomXPathImpl::disassemble_push_byte
    8846             :     , /* 0x42 */ &QDomXPathImpl::disassemble_push_double
    8847             :     , /* 0x43 */ &QDomXPathImpl::disassemble_push_double_zero
    8848             :     , /* 0x44 */ &QDomXPathImpl::disassemble_push_empty_node_set
    8849             :     , /* 0x45 */ &QDomXPathImpl::disassemble_push_empty_set
    8850             :     , /* 0x46 */ &QDomXPathImpl::disassemble_push_empty_string
    8851             :     , /* 0x47 */ &QDomXPathImpl::disassemble_push_end_of_arguments
    8852             :     , /* 0x48 */ &QDomXPathImpl::disassemble_push_false
    8853             :     , /* 0x49 */ &QDomXPathImpl::disassemble_push_large_string
    8854             :     , /* 0x4A */ &QDomXPathImpl::disassemble_push_long
    8855             :     , /* 0x4B */ &QDomXPathImpl::disassemble_push_longlong
    8856             :     , /* 0x4C */ &QDomXPathImpl::disassemble_push_medium_string
    8857             :     , /* 0x4D */ &QDomXPathImpl::disassemble_push_negative_byte
    8858             :     , /* 0x4E */ &QDomXPathImpl::disassemble_push_negative_short
    8859             :     , /* 0x4F */ &QDomXPathImpl::disassemble_push_negative_long
    8860             : 
    8861             :     , /* 0x50 */ &QDomXPathImpl::disassemble_push_short
    8862             :     , /* 0x51 */ &QDomXPathImpl::disassemble_push_small_string
    8863             :     , /* 0x52 */ &QDomXPathImpl::disassemble_push_true
    8864             :     , /* 0x53 */ &QDomXPathImpl::disassemble_push_zero
    8865             :     , /* 0x54 */ &QDomXPathImpl::disassemble_undefined_instruction
    8866             :     , /* 0x55 */ &QDomXPathImpl::disassemble_undefined_instruction
    8867             :     , /* 0x56 */ &QDomXPathImpl::disassemble_undefined_instruction
    8868             :     , /* 0x57 */ &QDomXPathImpl::disassemble_undefined_instruction
    8869             :     , /* 0x58 */ &QDomXPathImpl::disassemble_undefined_instruction
    8870             :     , /* 0x59 */ &QDomXPathImpl::disassemble_undefined_instruction
    8871             :     , /* 0x5A */ &QDomXPathImpl::disassemble_undefined_instruction
    8872             :     , /* 0x5B */ &QDomXPathImpl::disassemble_undefined_instruction
    8873             :     , /* 0x5C */ &QDomXPathImpl::disassemble_undefined_instruction
    8874             :     , /* 0x5D */ &QDomXPathImpl::disassemble_undefined_instruction
    8875             :     , /* 0x5E */ &QDomXPathImpl::disassemble_undefined_instruction
    8876             :     , /* 0x5F */ &QDomXPathImpl::disassemble_undefined_instruction
    8877             : 
    8878             :     , /* 0x60 */ &QDomXPathImpl::disassemble_add
    8879             :     , /* 0x61 */ &QDomXPathImpl::disassemble_and
    8880             :     , /* 0x62 */ &QDomXPathImpl::disassemble_ceiling
    8881             :     , /* 0x63 */ &QDomXPathImpl::disassemble_decrement
    8882             :     , /* 0x64 */ &QDomXPathImpl::disassemble_divide
    8883             :     , /* 0x65 */ &QDomXPathImpl::disassemble_equal
    8884             :     , /* 0x66 */ &QDomXPathImpl::disassemble_floor
    8885             :     , /* 0x67 */ &QDomXPathImpl::disassemble_greater_or_equal
    8886             :     , /* 0x68 */ &QDomXPathImpl::disassemble_greater_than
    8887             :     , /* 0x69 */ &QDomXPathImpl::disassemble_idivide
    8888             :     , /* 0x6A */ &QDomXPathImpl::disassemble_increment
    8889             :     , /* 0x6B */ &QDomXPathImpl::disassemble_less_or_equal
    8890             :     , /* 0x6C */ &QDomXPathImpl::disassemble_less_than
    8891             :     , /* 0x6D */ &QDomXPathImpl::disassemble_modulo
    8892             :     , /* 0x6E */ &QDomXPathImpl::disassemble_multiply
    8893             :     , /* 0x6F */ &QDomXPathImpl::disassemble_negate
    8894             : 
    8895             :     , /* 0x70 */ &QDomXPathImpl::disassemble_not
    8896             :     , /* 0x71 */ &QDomXPathImpl::disassemble_not_equal
    8897             :     , /* 0x72 */ &QDomXPathImpl::disassemble_or
    8898             :     , /* 0x73 */ &QDomXPathImpl::disassemble_round
    8899             :     , /* 0x74 */ &QDomXPathImpl::disassemble_string_length
    8900             :     , /* 0x75 */ &QDomXPathImpl::disassemble_subtract
    8901             :     , /* 0x76 */ &QDomXPathImpl::disassemble_undefined_instruction
    8902             :     , /* 0x77 */ &QDomXPathImpl::disassemble_undefined_instruction
    8903             :     , /* 0x78 */ &QDomXPathImpl::disassemble_undefined_instruction
    8904             :     , /* 0x79 */ &QDomXPathImpl::disassemble_undefined_instruction
    8905             :     , /* 0x7A */ &QDomXPathImpl::disassemble_undefined_instruction
    8906             :     , /* 0x7B */ &QDomXPathImpl::disassemble_undefined_instruction
    8907             :     , /* 0x7C */ &QDomXPathImpl::disassemble_undefined_instruction
    8908             :     , /* 0x7D */ &QDomXPathImpl::disassemble_undefined_instruction
    8909             :     , /* 0x7E */ &QDomXPathImpl::disassemble_undefined_instruction
    8910             :     , /* 0x7F */ &QDomXPathImpl::disassemble_undefined_instruction
    8911             : 
    8912             :     , /* 0x80 */ &QDomXPathImpl::disassemble_axis
    8913             :     , /* 0x81 */ &QDomXPathImpl::disassemble_root
    8914             :     , /* 0x82 */ &QDomXPathImpl::disassemble_get_node_set
    8915             :     , /* 0x83 */ &QDomXPathImpl::disassemble_set_node_set
    8916             :     , /* 0x84 */ &QDomXPathImpl::disassemble_get_result
    8917             :     , /* 0x85 */ &QDomXPathImpl::disassemble_set_result
    8918             :     , /* 0x86 */ &QDomXPathImpl::disassemble_get_position
    8919             :     , /* 0x87 */ &QDomXPathImpl::disassemble_set_position
    8920             :     , /* 0x88 */ &QDomXPathImpl::disassemble_node_set_size
    8921             :     , /* 0x89 */ &QDomXPathImpl::disassemble_merge_sets
    8922             :     , /* 0x8A */ &QDomXPathImpl::disassemble_predicate
    8923             :     , /* 0x8B */ &QDomXPathImpl::disassemble_create_node_context
    8924             :     , /* 0x8C */ &QDomXPathImpl::disassemble_get_context_node
    8925             :     , /* 0x8D */ &QDomXPathImpl::disassemble_next_context_node
    8926             :     , /* 0x8E */ &QDomXPathImpl::disassemble_pop_context
    8927             :     , /* 0x8F */ &QDomXPathImpl::disassemble_undefined_instruction
    8928             : 
    8929             :     , /* 0x90 */ &QDomXPathImpl::disassemble_undefined_instruction
    8930             :     , /* 0x91 */ &QDomXPathImpl::disassemble_undefined_instruction
    8931             :     , /* 0x92 */ &QDomXPathImpl::disassemble_undefined_instruction
    8932             :     , /* 0x93 */ &QDomXPathImpl::disassemble_undefined_instruction
    8933             :     , /* 0x94 */ &QDomXPathImpl::disassemble_undefined_instruction
    8934             :     , /* 0x95 */ &QDomXPathImpl::disassemble_undefined_instruction
    8935             :     , /* 0x96 */ &QDomXPathImpl::disassemble_undefined_instruction
    8936             :     , /* 0x97 */ &QDomXPathImpl::disassemble_undefined_instruction
    8937             :     , /* 0x98 */ &QDomXPathImpl::disassemble_undefined_instruction
    8938             :     , /* 0x99 */ &QDomXPathImpl::disassemble_undefined_instruction
    8939             :     , /* 0x9A */ &QDomXPathImpl::disassemble_undefined_instruction
    8940             :     , /* 0x9B */ &QDomXPathImpl::disassemble_undefined_instruction
    8941             :     , /* 0x9C */ &QDomXPathImpl::disassemble_undefined_instruction
    8942             :     , /* 0x9D */ &QDomXPathImpl::disassemble_undefined_instruction
    8943             :     , /* 0x9E */ &QDomXPathImpl::disassemble_undefined_instruction
    8944             :     , /* 0x9F */ &QDomXPathImpl::disassemble_undefined_instruction
    8945             : 
    8946             :     , /* 0xA0 */ &QDomXPathImpl::disassemble_undefined_instruction
    8947             :     , /* 0xA1 */ &QDomXPathImpl::disassemble_undefined_instruction
    8948             :     , /* 0xA2 */ &QDomXPathImpl::disassemble_undefined_instruction
    8949             :     , /* 0xA3 */ &QDomXPathImpl::disassemble_undefined_instruction
    8950             :     , /* 0xA4 */ &QDomXPathImpl::disassemble_undefined_instruction
    8951             :     , /* 0xA5 */ &QDomXPathImpl::disassemble_undefined_instruction
    8952             :     , /* 0xA6 */ &QDomXPathImpl::disassemble_undefined_instruction
    8953             :     , /* 0xA7 */ &QDomXPathImpl::disassemble_undefined_instruction
    8954             :     , /* 0xA8 */ &QDomXPathImpl::disassemble_undefined_instruction
    8955             :     , /* 0xA9 */ &QDomXPathImpl::disassemble_undefined_instruction
    8956             :     , /* 0xAA */ &QDomXPathImpl::disassemble_undefined_instruction
    8957             :     , /* 0xAB */ &QDomXPathImpl::disassemble_undefined_instruction
    8958             :     , /* 0xAC */ &QDomXPathImpl::disassemble_undefined_instruction
    8959             :     , /* 0xAD */ &QDomXPathImpl::disassemble_undefined_instruction
    8960             :     , /* 0xAE */ &QDomXPathImpl::disassemble_undefined_instruction
    8961             :     , /* 0xAF */ &QDomXPathImpl::disassemble_undefined_instruction
    8962             : 
    8963             :     , /* 0xB0 */ &QDomXPathImpl::disassemble_undefined_instruction
    8964             :     , /* 0xB1 */ &QDomXPathImpl::disassemble_undefined_instruction
    8965             :     , /* 0xB2 */ &QDomXPathImpl::disassemble_undefined_instruction
    8966             :     , /* 0xB3 */ &QDomXPathImpl::disassemble_undefined_instruction
    8967             :     , /* 0xB4 */ &QDomXPathImpl::disassemble_undefined_instruction
    8968             :     , /* 0xB5 */ &QDomXPathImpl::disassemble_undefined_instruction
    8969             :     , /* 0xB6 */ &QDomXPathImpl::disassemble_undefined_instruction
    8970             :     , /* 0xB7 */ &QDomXPathImpl::disassemble_undefined_instruction
    8971             :     , /* 0xB8 */ &QDomXPathImpl::disassemble_undefined_instruction
    8972             :     , /* 0xB9 */ &QDomXPathImpl::disassemble_undefined_instruction
    8973             :     , /* 0xBA */ &QDomXPathImpl::disassemble_undefined_instruction
    8974             :     , /* 0xBB */ &QDomXPathImpl::disassemble_undefined_instruction
    8975             :     , /* 0xBC */ &QDomXPathImpl::disassemble_undefined_instruction
    8976             :     , /* 0xBD */ &QDomXPathImpl::disassemble_undefined_instruction
    8977             :     , /* 0xBE */ &QDomXPathImpl::disassemble_undefined_instruction
    8978             :     , /* 0xBF */ &QDomXPathImpl::disassemble_undefined_instruction
    8979             : 
    8980             :     , /* 0xC0 */ &QDomXPathImpl::disassemble_undefined_instruction
    8981             :     , /* 0xC1 */ &QDomXPathImpl::disassemble_undefined_instruction
    8982             :     , /* 0xC2 */ &QDomXPathImpl::disassemble_undefined_instruction
    8983             :     , /* 0xC3 */ &QDomXPathImpl::disassemble_undefined_instruction
    8984             :     , /* 0xC4 */ &QDomXPathImpl::disassemble_undefined_instruction
    8985             :     , /* 0xC5 */ &QDomXPathImpl::disassemble_undefined_instruction
    8986             :     , /* 0xC6 */ &QDomXPathImpl::disassemble_undefined_instruction
    8987             :     , /* 0xC7 */ &QDomXPathImpl::disassemble_undefined_instruction
    8988             :     , /* 0xC8 */ &QDomXPathImpl::disassemble_undefined_instruction
    8989             :     , /* 0xC9 */ &QDomXPathImpl::disassemble_undefined_instruction
    8990             :     , /* 0xCA */ &QDomXPathImpl::disassemble_undefined_instruction
    8991             :     , /* 0xCB */ &QDomXPathImpl::disassemble_undefined_instruction
    8992             :     , /* 0xCC */ &QDomXPathImpl::disassemble_undefined_instruction
    8993             :     , /* 0xCD */ &QDomXPathImpl::disassemble_undefined_instruction
    8994             :     , /* 0xCE */ &QDomXPathImpl::disassemble_undefined_instruction
    8995             :     , /* 0xCF */ &QDomXPathImpl::disassemble_undefined_instruction
    8996             : 
    8997             :     , /* 0xD0 */ &QDomXPathImpl::disassemble_undefined_instruction
    8998             :     , /* 0xD1 */ &QDomXPathImpl::disassemble_undefined_instruction
    8999             :     , /* 0xD2 */ &QDomXPathImpl::disassemble_undefined_instruction
    9000             :     , /* 0xD3 */ &QDomXPathImpl::disassemble_undefined_instruction
    9001             :     , /* 0xD4 */ &QDomXPathImpl::disassemble_undefined_instruction
    9002             :     , /* 0xD5 */ &QDomXPathImpl::disassemble_undefined_instruction
    9003             :     , /* 0xD6 */ &QDomXPathImpl::disassemble_undefined_instruction
    9004             :     , /* 0xD7 */ &QDomXPathImpl::disassemble_undefined_instruction
    9005             :     , /* 0xD8 */ &QDomXPathImpl::disassemble_undefined_instruction
    9006             :     , /* 0xD9 */ &QDomXPathImpl::disassemble_undefined_instruction
    9007             :     , /* 0xDA */ &QDomXPathImpl::disassemble_undefined_instruction
    9008             :     , /* 0xDB */ &QDomXPathImpl::disassemble_undefined_instruction
    9009             :     , /* 0xDC */ &QDomXPathImpl::disassemble_undefined_instruction
    9010             :     , /* 0xDD */ &QDomXPathImpl::disassemble_undefined_instruction
    9011             :     , /* 0xDE */ &QDomXPathImpl::disassemble_undefined_instruction
    9012             :     , /* 0xDF */ &QDomXPathImpl::disassemble_undefined_instruction
    9013             : 
    9014             :     , /* 0xE0 */ &QDomXPathImpl::disassemble_undefined_instruction
    9015             :     , /* 0xE1 */ &QDomXPathImpl::disassemble_undefined_instruction
    9016             :     , /* 0xE2 */ &QDomXPathImpl::disassemble_undefined_instruction
    9017             :     , /* 0xE3 */ &QDomXPathImpl::disassemble_undefined_instruction
    9018             :     , /* 0xE4 */ &QDomXPathImpl::disassemble_undefined_instruction
    9019             :     , /* 0xE5 */ &QDomXPathImpl::disassemble_undefined_instruction
    9020             :     , /* 0xE6 */ &QDomXPathImpl::disassemble_undefined_instruction
    9021             :     , /* 0xE7 */ &QDomXPathImpl::disassemble_undefined_instruction
    9022             :     , /* 0xE8 */ &QDomXPathImpl::disassemble_undefined_instruction
    9023             :     , /* 0xE9 */ &QDomXPathImpl::disassemble_undefined_instruction
    9024             :     , /* 0xEA */ &QDomXPathImpl::disassemble_undefined_instruction
    9025             :     , /* 0xEB */ &QDomXPathImpl::disassemble_undefined_instruction
    9026             :     , /* 0xEC */ &QDomXPathImpl::disassemble_undefined_instruction
    9027             :     , /* 0xED */ &QDomXPathImpl::disassemble_undefined_instruction
    9028             :     , /* 0xEE */ &QDomXPathImpl::disassemble_undefined_instruction
    9029             :     , /* 0xEF */ &QDomXPathImpl::disassemble_undefined_instruction
    9030             : 
    9031             :     , /* 0xF0 */ &QDomXPathImpl::disassemble_undefined_instruction
    9032             :     , /* 0xF1 */ &QDomXPathImpl::disassemble_undefined_instruction
    9033             :     , /* 0xF2 */ &QDomXPathImpl::disassemble_undefined_instruction
    9034             :     , /* 0xF3 */ &QDomXPathImpl::disassemble_undefined_instruction
    9035             :     , /* 0xF4 */ &QDomXPathImpl::disassemble_undefined_instruction
    9036             :     , /* 0xF5 */ &QDomXPathImpl::disassemble_undefined_instruction
    9037             :     , /* 0xF6 */ &QDomXPathImpl::disassemble_undefined_instruction
    9038             :     , /* 0xF7 */ &QDomXPathImpl::disassemble_undefined_instruction
    9039             :     , /* 0xF8 */ &QDomXPathImpl::disassemble_undefined_instruction
    9040             :     , /* 0xF9 */ &QDomXPathImpl::disassemble_undefined_instruction
    9041             :     , /* 0xFA */ &QDomXPathImpl::disassemble_undefined_instruction
    9042             :     , /* 0xFB */ &QDomXPathImpl::disassemble_undefined_instruction
    9043             :     , /* 0xFC */ &QDomXPathImpl::disassemble_undefined_instruction
    9044             :     , /* 0xFD */ &QDomXPathImpl::disassemble_undefined_instruction
    9045             :     , /* 0xFE */ &QDomXPathImpl::disassemble_undefined_instruction
    9046             :     , /* 0xFF */ &QDomXPathImpl::disassemble_undefined_instruction
    9047             : };
    9048             : 
    9049             : 
    9050             : /** \class QDomXPath
    9051             :  * \brief A private class used to handle XPath expressions.
    9052             :  *
    9053             :  * This class parses the XPath expression and is capable of executing it
    9054             :  * against a QDomNode.
    9055             :  *
    9056             :  * The class is based on the XPath syntax as defined by the W3C consortium:
    9057             :  *
    9058             :  * http://www.w3.org/TR/xpath/#node-sets
    9059             :  *
    9060             :  * In a way, this is a rewrite of the QXmlQuery, except that this
    9061             :  * implementation can be used against a QDomNode and thus I can avoid all
    9062             :  * the problems with the QXmlQuery (i.e. having to convert the XML back to
    9063             :  * text so it can be used with QXmlQuery without crashing.)
    9064             :  *
    9065             :  * As per point "2 Basics" XQuery is a case-sensitive language so we read
    9066             :  * everything as is and test instructions in lowercase only as expected
    9067             :  * by the language. There are a few exceptions when testing certain values
    9068             :  * such as the contains of the lang attribute of the name of a processing
    9069             :  * instruction language (i.e "php" matches the language name in
    9070             :  * "&lt;?PHP ... ?&gt;").
    9071             :  *
    9072             :  * http://www.w3.org/TR/xquery/#id-basics
    9073             :  *
    9074             :  * \note
    9075             :  * All the expressions are not supported.
    9076             :  *
    9077             :  * The following is 'UnionExpr' and corresponding children rules as
    9078             :  * defined on the w3c website:
    9079             :  *
    9080             :  * \code
    9081             :  * Expr ::= OrExpr
    9082             :  *
    9083             :  * PrimaryExpr ::= VariableReference
    9084             :  *               | '(' Expr ')'
    9085             :  *               | Literal
    9086             :  *               | Number
    9087             :  *               | FunctionCall
    9088             :  *
    9089             :  * FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
    9090             :  *
    9091             :  * Argument ::= Expr
    9092             :  *
    9093             :  * OrExpr ::= AndExpr
    9094             :  *          | OrExpr 'or' AndExpr
    9095             :  *
    9096             :  * AndExpr ::= EqualityExpr
    9097             :  *          | AndExpr 'and' EqualityExpr
    9098             :  *
    9099             :  * EqualityExpr ::= RelationalExpr
    9100             :  *          | EqualityExpr '=' RelationalExpr
    9101             :  *          | EqualityExpr '!=' RelationalExpr
    9102             :  *
    9103             :  * RelationalExpr ::= AdditiveExpr
    9104             :  *          | RelationalExpr '<' AdditiveExpr
    9105             :  *          | RelationalExpr '>' AdditiveExpr
    9106             :  *          | RelationalExpr '<=' AdditiveExpr
    9107             :  *          | RelationalExpr '>=' AdditiveExpr
    9108             :  *
    9109             :  * AdditiveExpr ::= MultiplicativeExpr
    9110             :  *          | AdditiveExpr '+' MultiplicativeExpr
    9111             :  *          | AdditiveExpr '-' MultiplicativeExpr
    9112             :  *
    9113             :  * MultiplicativeExpr ::= UnaryExpr
    9114             :  *          | MultiplicativeExpr MultiplicativeOperator UnaryExpr
    9115             :  *          | MultiplicativeExpr 'div' UnaryExpr
    9116             :  *          | MultiplicativeExpr 'mod' UnaryExpr
    9117             :  *
    9118             :  * UnaryExpr ::= UnionExpr
    9119             :  *          | '-' UnaryExpr
    9120             :  *
    9121             :  * UnionExpr ::= PathExpr
    9122             :  *             | UnionExpr '|' PathExpr
    9123             :  *
    9124             :  * PathExpr ::= LocationPath
    9125             :  *            | FilterExpr
    9126             :  *            | FilterExpr '/' RelativeLocationPath
    9127             :  *            | FilterExpr '//' RelativeLocationPath
    9128             :  *
    9129             :  * FilterExpr ::= PrimaryExpr
    9130             :  *              | FilterExpr Predicate
    9131             :  *
    9132             :  * LocationPath ::= RelativeLocationPath
    9133             :  *                | AbsoluteLocationPath
    9134             :  *
    9135             :  * AbsoluteLocationPath ::= '/' RelativeLocationPath?
    9136             :  *                        | AbbreviatedAbsoluteLocationPath
    9137             :  *
    9138             :  * AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath
    9139             :  *
    9140             :  * RelativeLocationPath ::= Step
    9141             :  *                        | RelativeLocationPath '/' Step
    9142             :  *                        | AbbreviatedRelativeLocationPath
    9143             :  *
    9144             :  * AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
    9145             :  *
    9146             :  * Step ::= AxisSpecifier NodeTest Predicate*
    9147             :  *        | AbbreviatedStep
    9148             :  *
    9149             :  * AxisSpecifier ::= AxisName '::'
    9150             :  *                 | AbbreviatedAxisSpecifier
    9151             :  *
    9152             :  * AxisName ::= 'ancestor'
    9153             :  *            | 'ancestor-or-self'
    9154             :  *            | 'attribute'
    9155             :  *            | 'child'
    9156             :  *            | 'descendant'
    9157             :  *            | 'descendant-or-self'
    9158             :  *            | 'following'
    9159             :  *            | 'following-sibling'
    9160             :  *            | 'namespace'
    9161             :  *            | 'parent'
    9162             :  *            | 'preceding'
    9163             :  *            | 'preceding-sibling'
    9164             :  *            | 'self'
    9165             :  *
    9166             :  * NodeTest ::= NameTest
    9167             :  *            | NodeType '(' ')'
    9168             :  *            | 'processing-instruction' '(' Literal ')'
    9169             :  *
    9170             :  * Predicate ::= '[' PredicateExpr ']'
    9171             :  *
    9172             :  * PredicateExpr ::= Expr
    9173             :  *
    9174             :  * AbbreviatedStep ::= '.'
    9175             :  *                   | '..'
    9176             :  *
    9177             :  * AbbreviatedAxisSpecifier ::= '@'?
    9178             :  *
    9179             :  * ExprToken ::= '(' | ')'
    9180             :  *             | '[' | ']'
    9181             :  *             | '.'
    9182             :  *             | '..'
    9183             :  *             | '@'
    9184             :  *             | ','
    9185             :  *             | '::'
    9186             :  *             | NameTest
    9187             :  *             | NodeType
    9188             :  *             | Operator
    9189             :  *             | FunctionName
    9190             :  *             | AxisName
    9191             :  *             | Literal
    9192             :  *             | Number
    9193             :  *             | VariableReference
    9194             :  *
    9195             :  * Literal ::= '"' [^"]* '"'
    9196             :  *           | "'" [^']* "'"
    9197             :  *
    9198             :  * Number ::= Digits ('.' Digits?)?
    9199             :  *          | '.' Digits
    9200             :  *
    9201             :  * Digits ::= [0-9]+
    9202             :  *
    9203             :  * Operator ::= OperatorName
    9204             :  *            | MultiplyOperator
    9205             :  *            | '/'
    9206             :  *            | '//'
    9207             :  *            | '|'
    9208             :  *            | '+'
    9209             :  *            | '-'
    9210             :  *            | '='
    9211             :  *            | '!='
    9212             :  *            | '<'
    9213             :  *            | '<='
    9214             :  *            | '>'
    9215             :  *            | '>='
    9216             :  *
    9217             :  * OperatorName ::= 'and'
    9218             :  *                | 'or'
    9219             :  *                | 'mod'
    9220             :  *                | 'div'
    9221             :  *
    9222             :  * MultiplyOperator ::= '*'
    9223             :  *
    9224             :  * FunctionName ::= QName - NodeType
    9225             :  *
    9226             :  * VariableReference ::= '$' QName
    9227             :  *
    9228             :  * NameTest ::= '*'
    9229             :  *            | NCName ':' '*'
    9230             :  *            | QName
    9231             :  *
    9232             :  * NodeType ::= 'comment'
    9233             :  *            | 'text'
    9234             :  *            | 'processing-instruction'
    9235             :  *            | 'node'
    9236             :  *
    9237             :  * ExprWhitespace ::= S
    9238             :  *
    9239             :  * NCName ::= Name - (Char* ':' Char*)
    9240             :  *
    9241             :  * S ::= (#x20 | #x9 | #xD | #xA)+
    9242             :  *
    9243             :  * Char ::= #x9
    9244             :  *        | #xA
    9245             :  *        | #xD
    9246             :  *        | [#x20-#xD7FF]
    9247             :  *        | [#xE000-#xFFFD]
    9248             :  *        | [#x10000-#x10FFFF]
    9249             :  *
    9250             :  * NameStartChar ::= ':'
    9251             :  *                 | [A-Z]
    9252             :  *                 | '_'
    9253             :  *                 | [a-z]
    9254             :  *                 | [#xC0-#xD6]
    9255             :  *                 | [#xD8-#xF6]
    9256             :  *                 | [#xF8-#x2FF]
    9257             :  *                 | [#x370-#x37D]
    9258             :  *                 | [#x37F-#x1FFF]
    9259             :  *                 | [#x200C-#x200D]
    9260             :  *                 | [#x2070-#x218F]
    9261             :  *                 | [#x2C00-#x2FEF]
    9262             :  *                 | [#x3001-#xD7FF]
    9263             :  *                 | [#xF900-#xFDCF]
    9264             :  *                 | [#xFDF0-#xFFFD]
    9265             :  *                 | [#x10000-#xEFFFF]
    9266             :  *
    9267             :  * NameChar ::= NameStartChar
    9268             :  *            | '-'
    9269             :  *            | '.'
    9270             :  *            | [0-9]
    9271             :  *            | #xB7
    9272             :  *            | [#x0300-#x036F]
    9273             :  *            | [#x203F-#x2040]
    9274             :  *
    9275             :  * Name ::= NameStartChar (NameChar)*
    9276             :  *
    9277             :  * Names ::= Name (#x20 Name)*
    9278             :  *
    9279             :  * Nmtoken ::= (NameChar)+
    9280             :  *
    9281             :  * Nmtokens ::= Nmtoken (#x20 Nmtoken)*
    9282             :  *
    9283             :  * QName ::= PrefixedName
    9284             :  *         | UnprefixedName
    9285             :  *
    9286             :  * PrefixedName ::= Prefix ':' LocalPart
    9287             :  *
    9288             :  * UnprefixedName ::= LocalPart
    9289             :  *
    9290             :  * Prefix ::= NCName
    9291             :  *
    9292             :  * LocalPart ::= NCName
    9293             :  * \endcode
    9294             :  */
    9295             : 
    9296             : 
    9297             : 
    9298             : /** \brief Initialize the QDomXPath object.
    9299             :  *
    9300             :  * The constructor initializes the QDomXPath object. By default, the XPath
    9301             :  * is viewed as "." and the internal parameter (f_impl) is set to NULL
    9302             :  * until you call setXPath() or setProgram(). Once a program was defined,
    9303             :  * it is possible to apply an XML file against the XPath by calling the
    9304             :  * apply() functions.
    9305             :  *
    9306             :  * The array of variable is initialized, but it remains empty until you
    9307             :  * bind some variables to it with bindVariable().
    9308             :  *
    9309             :  * \sa bindVariable()
    9310             :  * \sa setXPath()
    9311             :  * \sa setProgram()
    9312             :  * \sa apply()
    9313             :  */
    9314           0 : QDomXPath::QDomXPath()
    9315             :     //: f_xpath("") -- auto-init
    9316           0 :     : f_impl(NULL)
    9317             :     //, f_variables() -- auto-init
    9318             : {
    9319           0 : }
    9320             : 
    9321             : 
    9322             : /** \brief Clean up the QDomXPath object.
    9323             :  *
    9324             :  * Since the f_impl variable member is defined in the qdomxpath.cpp, I
    9325             :  * cannot have it as a smart pointer in the qdomxpath.h file. For this
    9326             :  * reason, I manage it here.
    9327             :  */
    9328           0 : QDomXPath::~QDomXPath()
    9329             : {
    9330           0 :     delete f_impl;
    9331           0 : }
    9332             : 
    9333             : 
    9334             : /** \brief Set the XPath.
    9335             :  *
    9336             :  * This function sets the XPath of the QDomXPath object. By default, the
    9337             :  * XPath is set to "." (i.e. return the current node.)
    9338             :  *
    9339             :  * If the XPath is considered invalid, then this function returns false
    9340             :  * and the internal state is not changed. If considered valid, then the
    9341             :  * new XPath takes effect and the function returns true.
    9342             :  *
    9343             :  * Note that if xpath is set to the empty string or ".", it is always
    9344             :  * accepted and in both cases it represents the current node.
    9345             :  *
    9346             :  * \param[in] xpath  The new XPath to use in this QDomXPath.
    9347             :  * \param[in] show_commands  Show the assembly while compiling.
    9348             :  *
    9349             :  * \return true if the \p xpath is valid, false otherwise.
    9350             :  */
    9351           0 : bool QDomXPath::setXPath(const QString& xpath, bool show_commands)
    9352             : {
    9353           0 :     if(xpath.isEmpty() || xpath == ".")
    9354             :     {
    9355           0 :         f_xpath = "";
    9356           0 :         delete f_impl;
    9357           0 :         f_impl = NULL;
    9358           0 :         return true;
    9359             :     }
    9360             : 
    9361           0 :     QDomXPath::QDomXPathImpl *impl(new QDomXPath::QDomXPathImpl(this, xpath));
    9362             :     try
    9363             :     {
    9364           0 :         impl->parse(show_commands);
    9365             :     }
    9366           0 :     catch(...)
    9367             :     {
    9368           0 :         delete impl;
    9369           0 :         throw;
    9370             :     }
    9371             : 
    9372             :     // by contract this changes only at the very end of the function
    9373           0 :     f_xpath = xpath;
    9374           0 :     delete f_impl;
    9375           0 :     f_impl = impl;
    9376             : 
    9377           0 :     return true;
    9378             : }
    9379             : 
    9380             : 
    9381             : /** \brief Get the current xpath.
    9382             :  *
    9383             :  * This function returns the current XPath. If it was never set, then the
    9384             :  * function returns ".". Note that if the setXPath() function returns false,
    9385             :  * then the XPath doesn't get changed and thus this function returns the
    9386             :  * previous XPath.
    9387             :  *
    9388             :  * \return The XPath string, or "." if not yet defined.
    9389             :  */
    9390           0 : QString QDomXPath::getXPath() const
    9391             : {
    9392           0 :     if(f_xpath.isEmpty())
    9393             :     {
    9394           0 :         return ".";
    9395             :     }
    9396           0 :     return f_xpath;
    9397             : }
    9398             : 
    9399             : 
    9400             : /** \brief Apply the XPath against the specified node.
    9401             :  *
    9402             :  * This function applies (queries) the XPath that was previously set with
    9403             :  * the setXPath() function agains the input \p node parameter.
    9404             :  *
    9405             :  * The function returns a vector of nodes because it is not possible to
    9406             :  * add parameters to a QDomNodeList without being within the implementation
    9407             :  * (i.e. there is no function to add any node to the list.) This may be
    9408             :  * because a list of nodes is dynamic, it includes a way to remove the
    9409             :  * node from the list in the event the node gets deleted (just an assumption
    9410             :  * of course.)
    9411             :  *
    9412             :  * \todo
    9413             :  * We want to implement an apply() function that can return processed
    9414             :  * data so we could get a string or an integer instead of a list of
    9415             :  * nodes.
    9416             :  *
    9417             :  * \note
    9418             :  * If no program was loaded, this function returns its input as is.
    9419             :  *
    9420             :  * \note
    9421             :  * XPath does not modifies its input document.
    9422             :  *
    9423             :  * \param[in] node  The node to query.
    9424             :  *
    9425             :  * \return A list of nodes (maybe empty.)
    9426             :  */
    9427           0 : QDomXPath::node_vector_t QDomXPath::apply(QDomNode node) const
    9428             : {
    9429           0 :     node_vector_t nodes;
    9430           0 :     nodes.push_back(node);
    9431           0 :     if(f_impl)
    9432             :     {
    9433           0 :         return f_impl->apply(nodes);
    9434             :     }
    9435             :     // no f_impl means "." which is just this node
    9436           0 :     return nodes;
    9437             : }
    9438             : 
    9439             : 
    9440             : /** \brief Apply the XPath against the specified list of nodes.
    9441             :  *
    9442             :  * This function applies (queries) the XPath that was previously set with
    9443             :  * one of the setXPath() or setProgram() functions against the set of
    9444             :  * input nodes.
    9445             :  *
    9446             :  * \todo
    9447             :  * We want to implement an apply() function that can return processed
    9448             :  * data so we could get a string or an integer instead of a list of
    9449             :  * nodes.
    9450             :  *
    9451             :  * \note
    9452             :  * The different nodes in the node vector do not all need to be from the
    9453             :  * same document.
    9454             :  *
    9455             :  * \note
    9456             :  * If no program was loaded, this function returns its input as is.
    9457             :  *
    9458             :  * \note
    9459             :  * XPath does not modifies its input document.
    9460             :  *
    9461             :  * \param[in] nodes  The list of nodes to query.
    9462             :  *
    9463             :  * \return A list of nodes (maybe empty.)
    9464             :  */
    9465           0 : QDomXPath::node_vector_t QDomXPath::apply(node_vector_t nodes) const
    9466             : {
    9467           0 :     if(f_impl)
    9468             :     {
    9469           0 :         return f_impl->apply(nodes);
    9470             :     }
    9471             :     // no f_impl means "." which is just these nodes
    9472           0 :     return nodes;
    9473             : }
    9474             : 
    9475             : 
    9476             : /** \brief Disassemble the program.
    9477             :  *
    9478             :  * This function prints out the disassembled program in your stdout.
    9479             :  *
    9480             :  * The disassembled program shows the pointer counter (position inside the
    9481             :  * program) the instruction, and for PUSH instruction, the data getting
    9482             :  * pushed (i.e. a number or a string.)
    9483             :  *
    9484             :  * This function is used by the -d option of the cxpath compiler.
    9485             :  */
    9486           0 : void QDomXPath::disassemble() const
    9487             : {
    9488           0 :     if(f_impl)
    9489             :     {
    9490           0 :         f_impl->disassemble();
    9491             :     }
    9492             :     else
    9493             :     {
    9494           0 :         throw QDomXPathException_InternalError("error: no program to disassemble");
    9495             :     }
    9496           0 : }
    9497             : 
    9498             : 
    9499             : /** \brief Bind a variable to this DOM XPath.
    9500             :  *
    9501             :  * This function binds the variable named \p name to this XPath.
    9502             :  *
    9503             :  * Within the script, variable can be accessed using the $\<name> syntax.
    9504             :  *
    9505             :  * \note
    9506             :  * The bind function does not (yet) verify that the variable name is
    9507             :  * valid. It has to be a valid QName to work with the XPath. A QName
    9508             :  * is defined as an optional prefix, colon, and local-part:
    9509             :  *
    9510             :  * \code
    9511             :  * [ <prefix> ':' ] <local-part>
    9512             :  * \endcode
    9513             :  *
    9514             :  * \param[in] name  The name of the variable.
    9515             :  * \param[in] value  The value of the variable.
    9516             :  */
    9517           0 : void QDomXPath::bindVariable(const QString& name, const QString& value)
    9518             : {
    9519           0 :     f_variables[name] = value;
    9520           0 : }
    9521             : 
    9522             : 
    9523             : /** \brief Check whether a variable is defined.
    9524             :  *
    9525             :  * This function checks whether a variable is set. If so, the function
    9526             :  * returns true.
    9527             :  *
    9528             :  * Note that it is important for you to call this function if you'd like
    9529             :  * to get a variable contents and not throw if the variable does not
    9530             :  * exist:
    9531             :  *
    9532             :  * \code
    9533             :  * if(xpath->hasVariable(name))
    9534             :  * {
    9535             :  *   value = xpath->getVariable(name);
    9536             :  * }
    9537             :  * else
    9538             :  * {
    9539             :  *   value = "*"; // some default value
    9540             :  * }
    9541             :  * \endcode
    9542             :  *
    9543             :  * \param[in] name  The name of the variable to check.
    9544             :  *
    9545             :  * \return true if the variable is defined, false otherwise.
    9546             :  */
    9547           0 : bool QDomXPath::hasVariable(const QString& name)
    9548             : {
    9549           0 :     return f_variables.contains(name);
    9550             : }
    9551             : 
    9552             : 
    9553             : /** \brief Retrieve the variable.
    9554             :  *
    9555             :  * This function is used to retrieve the value of a variable bound with
    9556             :  * the XPath.
    9557             :  *
    9558             :  * It is used internally with the $\<QName\> syntax. Note that if a function
    9559             :  * is called, then that function's variables are checked first and will
    9560             :  * shadow the main variables.
    9561             :  *
    9562             :  * \exception QDomXPathException_UndefinedVariable
    9563             :  * If the variable does not exist then the function raises this exception.
    9564             :  * To avoid the exception, use the hasVariable() predicate first.
    9565             :  *
    9566             :  * \param[in] name  The name of the variable to retrieve.
    9567             :  *
    9568             :  * \return A copy of the variable contents as a string.
    9569             :  */
    9570           0 : QString QDomXPath::getVariable(const QString& name)
    9571             : {
    9572           0 :     if(!f_variables.contains(name))
    9573             :     {
    9574           0 :         throw QDomXPathException_UndefinedVariable(QString("variable \"%1\" is not defined").arg(name));
    9575             :     }
    9576           0 :     return f_variables[name];
    9577             : }
    9578             : 
    9579             : 
    9580             : /** \brief Set the program.
    9581             :  *
    9582             :  * When you store a previously compiled program somewhere (you can retrieve
    9583             :  * a compiled program with the getProgram() function), you can later reload
    9584             :  * it in your QDomXPath object with the setProgram() function.
    9585             :  *
    9586             :  * This is quite useful to compile many XPaths, save them in a file or
    9587             :  * your Qt resources, and later load them and pass them to this function
    9588             :  * for instant processing.
    9589             :  *
    9590             :  * Note that small XPaths may get compiled faster than the load from a file.
    9591             :  * It will be up to you to test what seems to be the fastest. Very large
    9592             :  * and complex XPaths are likely to benefit from a pre-compilation.
    9593             :  *
    9594             :  * \param[in] program  The program to save in this QDomXPath object.
    9595             :  * \param[in] show_commands  Whether the commands are shown in stdout while executing the program.
    9596             :  */
    9597           0 : void QDomXPath::setProgram(const QDomXPath::program_t& program, bool show_commands)
    9598             : {
    9599           0 :     if(f_impl == NULL)
    9600             :     {
    9601             :         // the original XPath is not known (although it could be saved
    9602             :         // in the program and restored?)
    9603           0 :         f_impl = new QDomXPath::QDomXPathImpl(this, "");
    9604             :     }
    9605           0 :     f_xpath = f_impl->setProgram(program, show_commands);
    9606           0 : }
    9607             : 
    9608             : 
    9609             : 
    9610             : /** \brief Retrieve the compiled program.
    9611             :  *
    9612             :  * The program can be retrieved after calling the setXPath() function.
    9613             :  * The program must be considered to be an array of bytes once outside
    9614             :  * of the QDomXPath environment.
    9615             :  *
    9616             :  * For the Unix 'file' tool trying to determine the type of a file, it
    9617             :  * can checks the first few bytes as:
    9618             :  *
    9619             :  * \li Byte 0 -- 'X'
    9620             :  * \li Byte 1 -- 'P'
    9621             :  * \li Byte 2 -- 'T'
    9622             :  * \li Byte 3 -- 'H'
    9623             :  * \li Byte 4 -- The major version, 0x01 or more (unsigned)
    9624             :  * \li Byte 5 -- The minor version, 0x00 or more (unsigned)
    9625             :  * \li Byte 6 -- higher size
    9626             :  * \li Byte 7 -- lower size
    9627             :  *
    9628             :  * The first 8 bytes are then followed by the original XPath so one can
    9629             :  * retrieve it, just in case. Bytes 6 and 7 represent the size of that
    9630             :  * XPath. If the XPath is more than 64Kb then only the first 65535 bytes
    9631             :  * are saved in the file.
    9632             :  *
    9633             :  * Note that it is possible to set byte 6 and 7 to zero and not save
    9634             :  * the XPath (this can be useful to save space.)
    9635             :  *
    9636             :  * \return A constant reference to the program.
    9637             :  */
    9638           0 : const QDomXPath::program_t& QDomXPath::getProgram() const
    9639             : {
    9640           0 :     if(f_impl)
    9641             :     {
    9642           0 :         return f_impl->getProgram();
    9643             :     }
    9644           0 :     throw QDomXPathException_InternalError("error: no program to retrieve");
    9645           6 : }
    9646             : 
    9647             : 
    9648             : 
    9649             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13