[4suite-checkins] [XPATH_OPTIMIZATIONS-branch] In 4Suite/Ft/Xml/XPath, files BuiltInExtFunctions.py, Context.py, Conversions.py, CoreFunctions.py, MathFunctions.py, MessageSource.py, NamespaceNode.py, ParsedAbbreviatedAbsoluteLocationPath.py, ParsedAbbreviatedRelativeLocationPath.py, ParsedAxisSpecifier.py, ParsedExpr.py, ParsedNodeTest.py, ParsedPredicateList.py, ParsedRelativeLocationPath.py, ParsedStep.py, Types.py, Util.py, XPath.bgen, XPathBase.bgen.frag, XPathLexerDefines.bgen.frag, XPathLexerPatterns.bgen.frag, XPathModules.bgen.frag, XPathParser.c, XPathParser.py, XPathTypes.py, _4xpath.py, __init__.py, _comparisons.c, _conversions.c, de.po, en_US.po

Jeremy Kloth jkloth at 4suite.org
Mon Dec 4 00:07:00 MST 2006


Branch: XPATH_OPTIMIZATIONS-branch

Modified Files:
    BuiltInExtFunctions.py Context.py Conversions.py CoreFunctions.py
    MathFunctions.py MessageSource.py
    ParsedAbbreviatedAbsoluteLocationPath.py
    ParsedAbbreviatedRelativeLocationPath.py ParsedAxisSpecifier.py
    ParsedExpr.py ParsedNodeTest.py ParsedPredicateList.py
    ParsedRelativeLocationPath.py ParsedStep.py Util.py XPath.bgen
    XPathBase.bgen.frag XPathLexerDefines.bgen.frag
    XPathLexerPatterns.bgen.frag XPathModules.bgen.frag XPathParser.c
    _4xpath.py __init__.py _conversions.c
Added Files:
    XPathTypes.py _comparisons.c
Removed Files:
    NamespaceNode.py Types.py XPathParser.py de.po en_US.po

Log Message:
Backports from HEAD

ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/BuiltInExtFunctions.py.diff?r1=1.52&r2=1.52.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/BuiltInExtFunctions.py?rev=1.52.2.1&content-type=text/vnd.viewcvs-markup

Index: BuiltInExtFunctions.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/BuiltInExtFunctions.py,v
retrieving revision 1.52
retrieving revision 1.52.2.1
diff -U2 -r1.52 -r1.52.2.1
--- BuiltInExtFunctions.py	2 Apr 2003 19:01:14 -0000	1.52
+++ BuiltInExtFunctions.py	4 Dec 2006 07:06:59 -0000	1.52.2.1
@@ -4,17 +4,27 @@
 4XPath-specific extension functions
 
-Copyright 2003 Fourthought, Inc. (USA).
+Copyright 2006 Fourthought, Inc. (USA).
 Detailed license and copyright information: http://4suite.org/COPYRIGHT
 Project home, documentation, distributions: http://4suite.org/
-"""
 
-import os, re, codecs, Ft
-import whrandom, urllib
+Extension functions are implemented by a module, such as this one,
+that defines an ExtFunctions global dictionary that maps (namespace,
+local-name) string tuples to a corresponding Python function. The
+function must take a Context object as the first argument, and any
+additional arguments accepted will correspond to the arguments passed
+in. See other API docs to see how to make use of modules that contain
+ExtFunctions.
+"""
 
+import os, re, codecs, time
 from xml.dom import Node
 
-from Ft.Lib import boolean, Uri, Wrap as LineWrap
+import Ft
+from Ft.Lib import boolean, number, Uri, Wrap as LineWrap
+from Ft.Lib.Random import DEFAULT_RNG
+from Ft.Xml import Lib
 from Ft.Xml.XPath import Conversions
-from Ft.Xml.XPath import FT_EXT_NAMESPACE, FT_OLD_EXT_NAMESPACE
+from Ft.Xml.XPath import XPathTypes as Types
+from Ft.Xml.XPath import FT_EXT_NAMESPACE
 
 
@@ -22,18 +32,19 @@
     """
     Returns the base URI of the first node in the given node-set, or
-    of the context node if no argument is given.
+    of the context node if no argument is given. If the given node-set
+    is empty, an empty string is returned.
     """
-    #FIXME: Arg must be a node set
-    if not arg:
-        arg = [context.node]
-    if hasattr(arg[0],'baseUri'):
-        return arg[0].baseUri
-    elif hasattr(arg[0],'refUri'):
-        return arg[0].refUri
-    elif hasattr(arg[0].ownerDocument,'baseUri'):
-        return arg[0].ownerDocument.refUri
-    elif hasattr(arg[0].ownerDocument,'refUri'):
-        return arg[0].ownerDocument.refUri
-    return ""
+    if arg is None:
+        node = context.node
+    elif isinstance(arg, Types.NodesetType):
+        if not arg:
+            return u''
+        node = arg[0]
+    else:
+        raise TypeError("%r must be a node-set, not a %s" % (
+            arg, Types.g_xpathPrimitiveTypes.get(type(arg), type(arg).__name__)))
+    return node.baseURI or u''
+BaseUri.arguments = (Types.NodesetType,)
+BaseUri.result = Types.StringType
 
 
@@ -46,4 +57,6 @@
     encode, decode, reader, writer = codecs.lookup(encoding)
     return decode(object)[0]
+Decode.arguments = (Types.ObjectType, Types.StringType)
+Decode.result = Types.ObjectType
 
 
@@ -56,4 +69,6 @@
     encode, decode, reader, writer = codecs.lookup(encoding)
     return encode(object)[0]
+Encode.arguments = (Types.ObjectType, Types.StringType)
+Encode.result = Types.ObjectType
 
 
@@ -66,22 +81,6 @@
     inner = Conversions.StringValue(inner)
     return outer.endswith(inner) and boolean.true or boolean.false
-
-
-def EnvVar(context, var):
-    """
-    Looks up a variable in the OS environment. Returns a string, either
-    the environment variable value or an empty string if there is no
-    such variable.
-    CAUTION: Using this function could be a security hazard.
-
-    You can also use system-property() for the same purpose
-    f:env-var('foo')
-    is equivalent to
-    system-property('fs:foo')
-    given a mapping from fs to http://xmlns.4suite.org/xslt/env-system-property
-    """
-    var = Conversions.StringValue(var)
-    result = os.environ.get(var, "")
-    return result
+EndsWith.arguments = (Types.StringType, Types.StringType)
+EndsWith.result = Types.BooleanType
 
 
@@ -93,4 +92,6 @@
     from xml.sax.saxutils import escape
     return escape(Conversions.StringValue(text))
+EscapeXml.arguments = (Types.StringType,)
+EscapeXml.result = Types.StringType
 
 
@@ -101,5 +102,8 @@
     from Ft.Lib import Uuid
     rt = Uuid.UuidAsString(Uuid.GenerateUuid())
+    rt = unicode(rt, 'us-ascii', errors='replace')
     return rt
+GenerateUuid.arguments = ()
+GenerateUuid.result = Types.StringType
 
 
@@ -119,6 +123,9 @@
     else:
         return v2
+If.arguments = (Types.BooleanType, Types.ObjectType, Types.ObjectType)
+If.result = Types.ObjectType
 
 
+# why does this exist?
 def ImportString(context, object):
     """
@@ -127,7 +134,10 @@
     this function might be extended to recover from this error)
     """
-    #FIXME: add validation of object as valid XPath string, and possibly mapping ops to PUA for illegal characters
+    #FIXME: Add validation of object as valid XPath string,
+    #and possibly mapping ops to PUA for illegal characters.
     #We probably need an Export string if we add PUA shifting
     return object
+ImportString.arguments = (Types.ObjectType,)
+ImportString.result = Types.StringType
 
 
@@ -149,4 +159,6 @@
     else:
         return text
+Indent.arguments = (Types.StringType, Types.NumberType, Types.StringType)
+Indent.result = Types.StringType
 
 
@@ -161,4 +173,6 @@
     text = text.replace("\r", "\n")
     return text
+NormalizeEol.arguments = (Types.StringType,)
+NormalizeEol.result = Types.StringType
 
 
@@ -168,21 +182,29 @@
     The result varies depending on the underlying operating system.
     """
-    from Ft.Lib import Uri
     return Uri.OsPathToUri(Conversions.StringValue(path))
+OsPath2Uri.arguments = (Types.StringType,)
+OsPath2Uri.result = Types.StringType
 
 
 def ParseXml(context, src, parameters=None):
-    #baseUri - is the optionsl URI to be used for the document in the parsing.
-    #          it is required if the string uses external entities or XInclude
     """
-    f:parse-xml() parses a given string as XML and returns a node set whose
-    sole item is the resulting parsed document root node.
+    f:parse-xml() parses the string-value of the given object as XML
+    and returns a node-set whose sole item is the resulting parsed
+    document's root node. The XML must be a well-formed document.
+
+    src - the string or object to be parsed as XML.
+
+    parameters - the name of a parameter set for the operation.
 
-    src    - converted to string value and parsed
-    params - the name of a parameter set for the operation
-             This argument is ignored for now, meaning the encoding must be UTF-8 and the XML must not use relative URIs in entities or XInclude
+    The parameters argument is ignored for now. In the future, it
+    will provide a way to specify a base URI for the resolution of
+    relative URIs in entity declarations and XIncludes.
+
+    Also for now, if the XML contains an encoding declaration, the
+    declaration must specify UTF-8.
 
     An example:
 
+    <?xml version="1.0" encoding="utf-8"?>
     <xsl:stylesheet
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
@@ -190,8 +212,10 @@
       version="1.0"
     >
-      <xsl:variable name="doc" select="'&lt;spam xmlns:x=&quot;http://spam.com&quot;>eggs&lt;monty>python&lt;/monty>&lt;/spam>'"/>
+      <xsl:output method="text"/>
+      <xsl:variable name="doc"
+        select="'&lt;spam>eggs&lt;monty>python&lt;/monty>&lt;/spam>'"/>
 
       <xsl:template match="/">
-      <xsl:value-of select="f:parse-xml($doc)/spam/monty"/>
+        <xsl:value-of select="f:parse-xml($doc)/spam/monty"/>
       </xsl:template>
     </xsl:stylesheet>
@@ -201,12 +225,26 @@
     python
 
-    See also: f:serialize-xml()
+    See also: XSLT (not XPath) extension function f:serialize-xml()
     """
     from Ft.Xml import Domlette
     src = Conversions.StringValue(src).encode("utf-8")
-    #Using FT_EXT_NAMESPACE as default URI is just a hack to avoid warnings
-    #doc = Domlette.NonvalidatingReader.parseString(src, baseUri or FT_EXT_NAMESPACE)
-    doc = Domlette.NonvalidatingReader.parseString(src, FT_EXT_NAMESPACE)
+
+    # prepare a base URI for the XML
+    instruction = getattr(context, 'currentInstruction', None)
+    if instruction:
+        uri = instruction.baseUri
+    else:
+        uri = context.node.baseUri
+    if not uri:
+        uri = OsPathToUri('__parse-xml-extension-function__',
+                          attemptAbsolute=1)
+    # append "XML-string-(something_unique)" as a fragment
+    uri += '%sXML-string-%s' % ((uri.find('#') + 1 and ';' or '#'),
+                                 str(time.time()))
+
+    doc = Domlette.NonvalidatingReader.parseString(src, uri)
     return [doc]
+ParseXml.arguments = (Types.StringType, Types.ObjectType)
+ParseXml.result = Types.NodesetType
 
 
@@ -220,12 +258,20 @@
     doc = context.node.rootNode
 
-    lo = Conversions.NumberValue(lo)
-    hi = Conversions.NumberValue(hi)
+    # sanity check
+    for n in (lo, hi):
+        if number.isinf(n) or number.isnan(n):
+            raise ValueError("Arguments to ft:range must be neither infinite nor NaN.")
+
+    #xrange wants int, not float
+    lo = int(round(Conversions.NumberValue(lo)))
+    hi = int(round(Conversions.NumberValue(hi)))
 
     nodeset = []
-    for number in xrange(lo, hi):
-        nodeset.append(doc.createTextNode(str(number)))
+    for num in xrange(lo, hi):
+        nodeset.append(doc.createTextNode(str(num)))
 
     return nodeset
+Range.arguments = (Types.NumberType, Types.NumberType)
+Range.result = Types.NodesetType
 
 
@@ -239,4 +285,6 @@
     rel = Conversions.StringValue(rel)
     return Uri.BaseJoin(base, rel)
+ResolvePath.arguments = (Types.StringType, Types.StringType)
+ResolvePath.result = Types.StringType
 
 
@@ -245,8 +293,14 @@
     Returns the relative URL ref given in the second argument
     resolved against the base given in the first argument.
+    In case of URI processing error an empty string is returned
     """
     base = Conversions.StringValue(base)
     rel = Conversions.StringValue(rel)
-    return Uri.BASIC_RESOLVER.normalize(rel, base)
+    try:
+        return Uri.Absolutize(rel, base)
+    except Uri.UriException:
+        return u''
+ResolveUrl.arguments = (Types.StringType, Types.StringType)
+ResolveUrl.result = Types.StringType
 
 
@@ -257,37 +311,29 @@
     http://www.itl.nist.gov/fipspubs/fip180-1.htm for info on SHA.
     """
+    text = Conversions.StringValue(text)
     import sha
-    return sha.sha(text).hexdigest()
+    rv = sha.sha(text).hexdigest()
+    rv = unicode(rv, 'us-ascii', errors='replace')
+    return rv
+ShaHash.arguments = (Types.StringType,)
+ShaHash.result = Types.StringType
 
 
 def SharePath(context):
     """
-    Returns the system-dependent path to Ft.Share
-    """
-    return Ft.SHARE_DIR
-
-
-def Spawnv(context, command, *args):
-    """
-    Executes a command in an operating system's shell, passing in the
-    command line arguments separately.
-    CAUTION: Using this function could be a security hazard.
-    See also: f:system()
+    Returns the system-dependent path to modifiable data
     """
-    command = Conversions.StringValue(command)
-    result = os.spawnv(os.P_WAIT, command, args)
-    return result
+    return unicode(Ft.GetConfigVar('LOCALSTATEDIR'), 'us-ascii',
+                   errors='replace')
+SharePath.arguments = ()
+SharePath.result = Types.StringType
 
-
-def System(context, command):
+def BinPath(context):
     """
-    Executes a command in the operating system's shell and returns the
-    command's output as a string.
-    CAUTION: Using this function could be a security hazard.
-    See also: f:spawnv()
+    Returns the system-dependent path of Fourthought binaries
     """
-    command = Conversions.StringValue(command)
-    result = os.system(command)
-    return result
+    return unicode(Ft.GetConfigVar('BINDIR'), 'us-ascii', errors='replace')
+BinPath.arguments = ()
+BinPath.result = Types.StringType
 
 
@@ -297,6 +343,7 @@
     The result varies depending on the underlying operating system.
     """
-    from Ft.Lib import Uri
     return Uri.UriToOsPath(Conversions.StringValue(uri))
+Uri2OsPath.arguments = (Types.StringType,)
+Uri2OsPath.result = Types.StringType
 
 
@@ -305,6 +352,7 @@
     Returns the 4Suite version number as a string.
     """
-    from Ft.__init__ import __version__
-    return __version__
+    return unicode(Ft.VERSION, 'us-ascii', errors='replace')
+Version.arguments = ()
+Version.result = Types.StringType
 
 
@@ -321,21 +369,25 @@
     width = Conversions.NumberValue(width)
     return LineWrap(s, width)
+Wrap.arguments = (Types.StringType, Types.NumberType)
+Wrap.result = Types.StringType
 
 
 def PytimeToExslt(context, t=None):
     """
-    Takes a Python timestamp number and returns a date/time as if from
-    EXSLT date-time()
+    Takes a Python time value as a number and returns a date/time as if
+    from EXSLT date-time()
     t - a time stamp number, as from Python's time.time()
         if omitted, use the current time
     """
     from Ft.Lib import Time as FtTime
-    if t:
+    if t is not None:
         t = Conversions.NumberValue(t)
-        return unicode(FtTime.FromPythonTime(t))
+        return unicode(str(FtTime.FromPythonTime(t)), errors='replace')
     else:
-        return unicode(FtTime.FromPythonTime())
+        return unicode(str(FtTime.FromPythonTime()), errors='replace')
+PytimeToExslt.arguments = (Types.NumberType,)
+PytimeToExslt.result = Types.StringType
+
 
-   
 #---EXSLT-like functions------------------------------------------------
 #   (perhaps soon to be deprecated)
@@ -353,5 +405,7 @@
         return delim.join(comps)
     else:
-        return ''.join(comps)
+        return u''.join(comps)
+Join.arguments = (Types.NodesetType, Types.StringType)
+Join.result = Types.StringType
 
 
@@ -368,4 +422,6 @@
     arg = Conversions.StringValue(arg)
     return re.match(pattern, arg) and boolean.true or boolean.false
+Match.arguments = (Types.StringType, Types.StringType)
+Match.result = Types.StringType
 
 
@@ -382,13 +438,15 @@
     #perhaps add some variants for missing time tuple values?
     str_time = time.strftime("%Y-%m-%dT%H:%M:%S", time_tuple)
-    return unicode(str_time)
+    return unicode(str_time, 'us-ascii', errors='replace')
+ParseDate.arguments = (Types.StringType, Types.StringType)
+ParseDate.result = Types.StringType
 
 
-def Random(context,max=None,forceInt=0):
+def Random(context, max=None, forceInt=0):
     """
-    Returns a random number between 0 and max (max defaults to 1).
-    The first optional argument is a different value for max, and
-    the second argument is a flag that, if set, causes the random
-    number to be an integer.
+    Returns a random number between 0 (inclusive) and max (exclusive).
+    max defaults to 1. The first optional argument is a different
+    value for max, and the second argument is a flag that, if set,
+    causes the random number to be rounded to an integer.
     See also: EXSLT's math:random()
     """
@@ -396,10 +454,11 @@
         max = Conversions.NumberValue(max)
     else:
-        max = 1
-    rt = whrandom.random()*max
+        max = 1.0
+    rt = DEFAULT_RNG.randrange(0, max)
     if forceInt:
-        #rt = int(rt)
         rt = round(rt)
     return rt
+Random.arguments = (Types.NumberType, Types.BooleanType)
+Random.result = Types.NumberType
 
 
@@ -418,93 +477,82 @@
     new = Conversions.StringValue(new)
     return arg.replace(old, new)
+Replace.arguments = (Types.StringType, Types.StringType, Types.StringType)
+Replace.result = Types.StringType
 
 
-
-#---deprecated functions------------------------------------------------
-
-def Distinct(context, nodeset):
+def StrFTime(context, format, date=None):
     """
-    DEPRECATED.
-    Equivalent to EXSLT's set:distinct()
+    Returns the given ISO 8601 UTC date-time formatted according to
+    the given format string as would be used by Python's
+    time.strftime(). If no date-time string is given, the current
+    time is used.
     """
-    # contributed by Lars Marius Garshol;
-    # originally using namespace URI 'http://garshol.priv.no/symbolic/'
-    if type(nodeset) != type([]):
-        #FIXME: l10n
-        raise Exception("argument for 'distinct' must be of type node-set!")
-
-    # Hey, why isn't set:distinct() implemented this way?
-    nodes = {}
-    for node in nodeset:
-        nodes[Conversions.StringValue(node)] = node
+    format = Conversions.StringValue(format)
+    if date is not None:
+        date = Conversions.StringValue(date)
+        time_str = time.strftime(format, time.strptime(date, '%Y-%m-%dT%H:%M:%SZ'))
+    else:
+        time_str = time.strftime(format)
+    return unicode(time_str, 'us-ascii', errors='replace')
+StrFTime.arguments = (Types.StringType, Types.StringType)
+StrFTime.result = Types.StringType
 
-    return nodes.values()
 
+#---OS System-aware functions------------------------------------------------
+#   (Not loaded by default for security reasons)
 
-def EscapeUrl(context, url):
-    """
-    DEPRECATED.
-    Equivalent to EXSLT's str:encode-uri()
-    Returns the given string escaped as appropriate for inclusion in a
-    URL. Relies on urllib.quote, so it does not correctly handle
-    non-ASCII characters above U+00FF.
+def EnvVar(context, var):
     """
-    return urllib.quote(Conversions.StringValue(url))
+    Looks up a variable in the OS environment. Returns a string, either
+    the environment variable value or an empty string if there is no
+    such variable. The system default encoding is assumed.
 
+    CAUTION: Using this function could be a security hazard.
 
-def Evaluate(context, expr):
-    """
-    DEPRECATED.
-    Equivalent to EXSLT's dyn:evaluate().
+    You can also use system-property() for the same purpose
+    f:env-var('foo')
+    is equivalent to
+    system-property('fs:foo')
+    given a mapping from fs to http://xmlns.4suite.org/xslt/env-system-property
     """
-    from Ft.Xml.XPath import parser
-    return parser.new().parse(Conversions.StringValue(expr)).evaluate(context)
+    var = Conversions.StringValue(var)
+    result = os.environ.get(var, '')
+    result = unicode(result, errors='replace')
+    return result
+EnvVar.arguments = (Types.StringType,)
+EnvVar.result = Types.StringType
 
 
-def Find(context, outer, inner):
-    """
-    DEPRECATED.
-    Returns the index of the first occurrence of one string in another.
-    Equivalent to string-length(substring-before($arg1,$arg2))-1.
+def Spawnv(context, command, *args):
     """
-    # contributed by Lars Marius Garshol;
-    # originally using namespace URI 'http://garshol.priv.no/symbolic/'
-    return Conversions.StringValue(outer).find(Conversions.StringValue(inner))
+    Executes a command in the operating system's shell, passing in the
+    command line arguments separately. Returns the result of the command
+    (a numeric exit code, typically).
 
+    CAUTION: Using this function could be a security hazard.
 
-def IsoTime(context):
+    See also: f:system()
     """
-    DEPRECATED.
-    Equivalent to EXSLT's date:date-time() wrapped in substring().
-    Returns the current, local date and time in ISO 8601 format
-    without time zone information, e.g. '2003-01-01T12:00:00'.
-    If you want just the date or time, use
-    substring-before(isotime(), 'T') or
-    substring-after(isotime(), 'T')
-    """
-    #try:
-    #    import DateTime
-    #    d = DateTime.now()
-    #    iso_time = DateTime.ISO.str(d)
-    #except ImportError:
-    import time
-    #(Y, M, D, h, m, s, d, j, dst) = time.localtime()
-    t_tuple = time.localtime()
-    iso_time = "%04i-%02i-%02iT%02i:%02i:%02i"%(t_tuple[:6])
-    return iso_time
+    command = Conversions.StringValue(command)
+    result = os.spawnv(os.P_WAIT, command, args)
+    return result
+Spawnv.arguments = (Types.StringType,)
+Spawnv.result = Types.NumberType
 
 
-def NodeSet(context, rtf):
+def System(context, command):
     """
-    DEPRECATED.
-    Equivalent to EXSLT's exsl:node-set().
+    Executes a command in the operating system's shell and returns the
+    command's result (a numeric exit code, typically).
+
+    CAUTION: Using this function could be a security hazard.
+
+    See also: f:spawnv()
     """
-    if type(rtf) == type([]):
-        return rtf
-    if hasattr(rtf,'nodeType') and rtf.nodeType == Node.DOCUMENT_NODE:
-        node_set = list(rtf.childNodes)
-    else:
-        node_set = [rtf]
-    return node_set
+    command = Conversions.StringValue(command)
+    result = os.system(command)
+    return result
+System.arguments = (Types.StringType,)
+System.result = Types.NumberType
 
 
@@ -518,5 +566,4 @@
     (FT_EXT_NAMESPACE, 'encode') : Encode,
     (FT_EXT_NAMESPACE, 'ends-with'): EndsWith,
-    (FT_EXT_NAMESPACE, 'env-var'): EnvVar,
     (FT_EXT_NAMESPACE, 'escape-xml'): EscapeXml,
     (FT_EXT_NAMESPACE, 'generate-uuid'): GenerateUuid,
@@ -528,8 +575,6 @@
     (FT_EXT_NAMESPACE, 'normalize-eol') : NormalizeEol,
     (FT_EXT_NAMESPACE, 'ospath2uri'): OsPath2Uri,
-    
     (FT_EXT_NAMESPACE, 'parse-date'): ParseDate,
     (FT_EXT_NAMESPACE, 'pytime-to-exslt'): PytimeToExslt,
-    
     (FT_EXT_NAMESPACE, 'parse-xml') : ParseXml,
     (FT_EXT_NAMESPACE, 'random'): Random,
@@ -540,25 +585,27 @@
     (FT_EXT_NAMESPACE, 'sha-hash') : ShaHash,
     (FT_EXT_NAMESPACE, 'share-path'): SharePath,
-    (FT_EXT_NAMESPACE, 'spawnv'): Spawnv,
-    (FT_EXT_NAMESPACE, 'system'): System,
+    (FT_EXT_NAMESPACE, 'bin-path'): BinPath,
     (FT_EXT_NAMESPACE, 'uri2ospath'): Uri2OsPath,
     (FT_EXT_NAMESPACE, 'version'): Version,
     (FT_EXT_NAMESPACE, 'wrap') : Wrap,
+    (FT_EXT_NAMESPACE, 'strftime') : StrFTime,
     }
 
 
-import MathFunctions
+InsecureExtFunctions = {
+    (FT_EXT_NAMESPACE, 'spawnv'): Spawnv,
+    (FT_EXT_NAMESPACE, 'system'): System,
+    (FT_EXT_NAMESPACE, 'env-var'): EnvVar,
+}
 
+import MathFunctions
 ExtFunctions.update(MathFunctions.ExtFunctions)
 
-DeprecatedFunctions = {
-    (FT_EXT_NAMESPACE, 'escape-url'): EscapeUrl,
-    (FT_EXT_NAMESPACE, 'evaluate'): Evaluate,
-    (FT_EXT_NAMESPACE, 'iso-time'): IsoTime,
-    (FT_EXT_NAMESPACE, 'distinct'): Distinct,
-    (FT_EXT_NAMESPACE, 'find'): Find,
-    (FT_EXT_NAMESPACE, 'node-set'): NodeSet,
-    }
-
-ExtFunctions.update(DeprecatedFunctions)
-
+# Deprecated functions removed for 4Suite 1.0a4:
+#
+#    (FT_EXT_NAMESPACE, 'escape-url'): EscapeUrl,
+#    (FT_EXT_NAMESPACE, 'evaluate'): Evaluate,
+#    (FT_EXT_NAMESPACE, 'iso-time'): IsoTime,
+#    (FT_EXT_NAMESPACE, 'distinct'): Distinct,
+#    (FT_EXT_NAMESPACE, 'find'): Find,
+#    (FT_EXT_NAMESPACE, 'node-set'): NodeSet,
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/Context.py.diff?r1=1.9&r2=1.9.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/Context.py?rev=1.9.2.1&content-type=text/vnd.viewcvs-markup

Index: Context.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/Context.py,v
retrieving revision 1.9
retrieving revision 1.9.2.1
diff -U2 -r1.9 -r1.9.2.1
--- Context.py	2 Mar 2003 17:44:34 -0000	1.9
+++ Context.py	4 Dec 2006 07:06:59 -0000	1.9.2.1
@@ -1,18 +1,17 @@
 ########################################################################
-#
-# File Name:   Context.py
-#
-# Docs:        http://docs.4suite.org/XPATH/Context.py.html
-#
+# $Header$
 """
-The context of an XPath expression.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+The context of an XPath expression
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-import types
+from types import ModuleType
 import CoreFunctions, BuiltInExtFunctions
+from Ft.Xml import XML_NAMESPACE
+
+__all__ = ['Context']
 
 class Context:
@@ -20,5 +19,5 @@
     functions.update(BuiltInExtFunctions.ExtFunctions)
     currentInstruction = None
-    
+
     def __init__(self,
                  node,
@@ -34,6 +33,5 @@
         self.varBindings = varBindings or {}
         self.processorNss = processorNss or {}
-
-        self._documentIndex = {}
+        self.processorNss.update({'xml': XML_NAMESPACE})
 
         # This may get mutated during processing
@@ -44,7 +42,7 @@
             for module in extModuleList:
                 if module:
-                    if not isinstance(module, types.ModuleType):
+                    if not isinstance(module, ModuleType):
                         module = __import__(module, {}, {}, ['ExtFunctions'])
-                    
+
                     if hasattr(module, 'ExtFunctions'):
                         functions.update(module.ExtFunctions)
@@ -66,17 +64,4 @@
         return
 
-    # Used for SortDocOrder with a nodeset containing multiple documents
-    def addDocument(self, document):
-        if not self._documentIndex.has_key(document):
-            self._documentIndex[document] = len(self._documentIndex)
-        return
-
-    # Used for SortDocOrder with a nodeset containing multiple documents
-    def compareDocuments(self, a, b):
-        # Make sure the documents we are comparing have an index
-        a = self._documentIndex.setdefault(a, len(self._documentIndex))
-        b = self._documentIndex.setdefault(b, len(self._documentIndex))
-        return cmp(a, b)
-    
     def copy(self):
         return (self.node, self.position, self.size)
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/Conversions.py.diff?r1=1.15&r2=1.15.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/Conversions.py?rev=1.15.2.1&content-type=text/vnd.viewcvs-markup

Index: Conversions.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/Conversions.py,v
retrieving revision 1.15
retrieving revision 1.15.2.1
diff -U2 -r1.15 -r1.15.2.1
--- Conversions.py	5 Dec 2002 21:08:44 -0000	1.15
+++ Conversions.py	4 Dec 2006 07:06:59 -0000	1.15.2.1
@@ -1,14 +1,10 @@
 ########################################################################
-#
-# File Name:   Conversions.py
-#
-# Docs:        http://docs.4suite.org/XPATH/Conversions.py.html
-#
+# $Header$
 """
 The implementation of the XPath object type conversions.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2000-2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
@@ -26,29 +22,29 @@
 # -- String Conversions ----------------------------------------------
 
-def _strUnknown(object):
+def _strUnknown(obj):
     # Allow for non-instance DOM node objects
-    if hasattr(object, 'nodeType'):
+    if hasattr(obj, 'nodeType'):
         # Add this type to the mapping for next time through
-        _strConversions[type(object)] = _strInstance
-        return _strInstance(object)
+        _strConversions[type(obj)] = _strInstance
+        return _strInstance(obj)
     return u''
 
-def _strInstance(object):
-    if hasattr(object, 'stringValue'):
-        return object.stringValue
-    elif hasattr(object, 'nodeType'):
-        node_type = object.nodeType
+def _strInstance(obj):
+    if hasattr(obj, 'stringValue'):
+        return obj.stringValue
+    elif hasattr(obj, 'nodeType'):
+        node_type = obj.nodeType
         if node_type in [Node.ELEMENT_NODE, Node.DOCUMENT_NODE]:
             # The concatenation of all text descendants
             text_elem_children = filter(lambda x:
                                         x.nodeType in [Node.TEXT_NODE, Node.ELEMENT_NODE],
-                                        object.childNodes)
+                                        obj.childNodes)
             return reduce(lambda x, y: StringValue(x) + StringValue(y),
                           text_elem_children,
                           '')
         if node_type in [Node.ATTRIBUTE_NODE, NAMESPACE_NODE]:
-            return object.value
+            return obj.value
         if node_type in [Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE]:
-            return object.data
+            return obj.data
     return u''
 
@@ -68,12 +64,12 @@
 
 _strConversions = {
-    types.StringType : unicode,
-    types.UnicodeType : unicode,
-    types.IntType : lambda i: unicode(str(i)),
-    types.LongType : lambda l: unicode(str(l)),
-    types.FloatType : _strFloat,
+    str : unicode,
+    unicode : unicode,
+    int : lambda i: unicode(str(i)),
+    long : lambda l: unicode(str(l)),
+    float : _strFloat,
     boolean.BooleanType : lambda b: unicode(str(b)),
     types.InstanceType : _strInstance,
-    types.ListType : lambda x: x and _strConversions.get(type(x[0]), _strUnknown)(x[0]) or u'',
+    list : lambda x: x and _strConversions.get(type(x[0]), _strUnknown)(x[0]) or u'',
 }
 
@@ -93,13 +89,13 @@
         return number.nan
 
-_numUnknown = lambda object: _numString(StringValue(object))
+_numUnknown = lambda obj: _numString(StringValue(obj))
 
 _numConversions = {
-    types.IntType : float,
-    types.LongType : float,
-    types.FloatType : float,
+    int : float,
+    long : float,
+    float : float,
     boolean.BooleanType : float,
-    types.StringType : _numString,
-    types.UnicodeType : _numString,
+    str : _numString,
+    unicode : _numString,
 }
 
@@ -108,13 +104,13 @@
 _boolConversions = {
     boolean.BooleanType : boolean.bool,
-    types.IntType : boolean.bool,
-    types.LongType : boolean.bool,
-    types.FloatType : boolean.bool,
-    types.StringType : boolean.bool,
-    types.UnicodeType : boolean.bool,
-    types.ListType : boolean.bool,
+    int : boolean.bool,
+    long : boolean.bool,
+    float : boolean.bool,
+    str : boolean.bool,
+    unicode : boolean.bool,
+    list : boolean.bool,
     }
 
-_boolUnknown = lambda object: boolean.bool(StringValue(object))
+_boolUnknown = lambda obj: boolean.bool(StringValue(obj))
 
 try:
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/CoreFunctions.py.diff?r1=1.17&r2=1.17.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/CoreFunctions.py?rev=1.17.2.1&content-type=text/vnd.viewcvs-markup

Index: CoreFunctions.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/CoreFunctions.py,v
retrieving revision 1.17
retrieving revision 1.17.2.1
diff -U2 -r1.17 -r1.17.2.1
--- CoreFunctions.py	23 Mar 2003 20:48:31 -0000	1.17
+++ CoreFunctions.py	4 Dec 2006 07:06:59 -0000	1.17.2.1
@@ -1,44 +1,23 @@
 ########################################################################
-#
-# File Name:   CoreFunctions.py
-#
-# Docs:        http://docs.4suite.org/XPATH/CoreFunctions.py.html
-#
+# $Header$
 """
-The implementation of all of the core functions for the XPath spec.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+The implementation of the core functions from XPath 1.0.
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2006 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-import cStringIO, types
+import warnings
 
 from xml.dom import Node
-from Ft.Xml import EMPTY_NAMESPACE
-from Ft.Lib import number, boolean
-from Ft.Xml.XPath import NamespaceNode
-from Ft.Xml.XPath import NaN, Inf
-from Ft.Xml.XPath import Util, Conversions
-from Ft.Xml.XPath import NAMESPACE_NODE
-from Ft.Xml.XPath import CompiletimeException, RuntimeException
 
-try:
-    import os, gettext
-    locale_dir = os.path.split(__file__)[0]
-    gettext.install('4Suite', locale_dir)
-#except ImportError, IOError:
-#Note, 1.5.2 has gettext, but no install
-except (ImportError, AttributeError, IOError):
-    def _(msg):
-        return msg
-
-
-class Types:
-    NumberType = 0
-    StringType = 1
-    BooleanType = 2
-    NodeSetType = 3
-    ObjectType = 4
+from Ft import TranslateMessage as _
+from Ft.Lib import number, boolean, Set
+from Ft.Xml import EMPTY_NAMESPACE, XML_NAMESPACE
+from Ft.Xml.XPath import NAMESPACE_NODE
+from Ft.Xml.XPath import Conversions, RuntimeException
+from Ft.Xml.XPath.XPathTypes import NodesetType, NumberType
+from Ft.Xml.XPath.XPathTypes import StringType as XPathStringType
 
 ### Node Set Functions ###
@@ -46,44 +25,35 @@
 def Last(context):
     """Function: <number> last()"""
-    return context.size
+    return float(context.size)
 
 
 def Position(context):
     """Function: <number> position()"""
-    return context.position
+    return float(context.position)
 
 
 def Count(context, nodeSet):
     """Function: <number> count(<node-set>)"""
-    if type(nodeSet) != type([]):
-        raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'count', _("expected node set argument"))
-    return len(nodeSet)
+    if not isinstance(nodeSet, NodesetType):
+        raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'count',
+                               _("expected node-set argument"))
+    return float(len(nodeSet))
 
 
-def Id(context, object):
+def Id(context, object_):
     """Function: <node-set> id(<object>)"""
-    id_list = []
-    if type(object) != type([]):
-        st = Conversions.StringValue(object)
+    if not isinstance(object_, NodesetType):
+        st = Conversions.StringValue(object_)
         id_list = st.split()
     else:
-        for n in object:
-            id_list.append(Conversions.StringValue(n))
+        id_list = [ Conversions.StringValue(n) for n in object_ ]
 
+    id_list = Set.Unique(id_list)
     doc = context.node.rootNode
-    getElementById = getattr(doc, 'getElementById', None)
-    if not getElementById:
-        getElementById = lambda id, d=doc, f=Util.GetElementById: f(d, id)
-
     nodeset = []
     for id in id_list:
-        try:
-            element = getElementById(id)
-            if element:
-                nodeset.append(element)
-        except ValueError:
-            # This exception will only occur from Util.GetElementById
-            raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'id',
-                                   _("argument not unique"))
+        element = doc.getElementById(id)
+        if element:
+            nodeset.append(element)
     return nodeset
 
@@ -93,10 +63,11 @@
     if nodeSet is None:
         node = context.node
+    elif not isinstance(nodeSet, NodesetType):
+        raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'local-name',
+                               _("expected node-set"))
+    elif not nodeSet:
+        return u''
     else:
-        if type(nodeSet) != type([]):
-            raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'local-name', _("expected node set"))
-        nodeSet = Util.SortDocOrder(context, nodeSet)
-        if type(nodeSet) != type([]) or len(nodeSet) == 0:
-            return u''
+        nodeSet.sort()
         node = nodeSet[0]
 
@@ -118,10 +89,11 @@
     if nodeSet is None:
         node = context.node
+    elif not isinstance(nodeSet, NodesetType):
+        raise RuntimeException(RuntimeException.WRONG_ARGUMENTS,
+                               'namespace-uri', _("expected node-set"))
+    elif not nodeSet:
+        return u''
     else:
-        if type(nodeSet) != type([]):
-            raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'namespace-uri', _("expected node set"))
-        nodeSet = Util.SortDocOrder(context, nodeSet)
-        if type(nodeSet) != type([]) or len(nodeSet) == 0:
-            return u''
+        nodeSet.sort()
         node = nodeSet[0]
 
@@ -137,10 +109,11 @@
     if nodeSet is None:
         node = context.node
+    elif not isinstance(nodeSet, NodesetType):
+        raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'name',
+                               _("expected node-set"))
+    elif not nodeSet:
+        return u''
     else:
-        if type(nodeSet) != type([]):
-            raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'name', _("expected node set"))
-        nodeSet = Util.SortDocOrder(context, nodeSet)
-        if type(nodeSet) != type([]) or len(nodeSet) == 0:
-            return u''
+        nodeSet.sort()
         node = nodeSet[0]
 
@@ -159,11 +132,11 @@
 ### String Functions ###
 
-def String(context, object=None):
+def String(context, object_=None):
     """Function: <string> string(<object>?)"""
-    if type(object) is types.UnicodeType:
-        return object
-    if object is None:
-        object = context.node
-    return Conversions.StringValue(object)
+    if isinstance(object_, XPathStringType):
+        return object_
+    if object_ is None:
+        object_ = context.node
+    return Conversions.StringValue(object_)
 
 
@@ -172,11 +145,15 @@
     if len(args) < 1:
         raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'concat', _("at least 2 arguments expected"))
-    return reduce(lambda a, b: a + Conversions.StringValue(b), args, '')
+    return reduce(lambda a, b: a + Conversions.StringValue(b), args, u'')
 
 
 def StartsWith(context, outer, inner):
     """Function: <string> starts-with(<string>, <string>)"""
-    outer = Conversions.StringValue(outer)
-    inner = Conversions.StringValue(inner)
+    if not isinstance(outer, XPathStringType):
+        outer = Conversions.StringValue(outer)
+    if not isinstance(inner, XPathStringType):
+        inner = Conversions.StringValue(inner)
+    if not inner:
+        return boolean.true
     return outer[:len(inner)] == inner and boolean.true or boolean.false
 
@@ -184,8 +161,10 @@
 def Contains(context, outer, inner):
     """Function: <string> contains(<string>, <string>)"""
-    if type(outer) is not types.UnicodeType:
+    if not isinstance(outer, XPathStringType):
         outer = Conversions.StringValue(outer)
-    if type(inner) is not types.UnicodeType:
+    if not isinstance(inner, XPathStringType):
         inner = Conversions.StringValue(inner)
+    if not inner:
+        return boolean.true
     return outer.find(inner) >= 0 and boolean.true or boolean.false
 
@@ -193,8 +172,10 @@
 def SubstringBefore(context, outer, inner):
     """Function: <string> substring-before(<string>, <string>)"""
-    if type(outer) is not types.UnicodeType:
+    if not isinstance(outer, XPathStringType):
         outer = Conversions.StringValue(outer)
-    if type(inner) is not types.UnicodeType:
+    if not isinstance(inner, XPathStringType):
         inner = Conversions.StringValue(inner)
+    if not inner:
+        return u''
     index = outer.find(inner)
     if index == -1:
@@ -205,8 +186,10 @@
 def SubstringAfter(context, outer, inner):
     """Function: <string> substring-after(<string>, <string>)"""
-    if type(outer) is not types.UnicodeType:
+    if not isinstance(outer, XPathStringType):
         outer = Conversions.StringValue(outer)
-    if type(inner) is not types.UnicodeType:
+    if not isinstance(inner, XPathStringType):
         inner = Conversions.StringValue(inner)
+    if not inner:
+        return u''
     index = outer.find(inner)
     if index == -1:
@@ -215,33 +198,51 @@
 
 
-def Substring(context, string, start, length=None):
+def Substring(context, st, start, length=None):
     """Function: <string> substring(<string>, <number>, <number>?)"""
-    if type(string) is not types.UnicodeType:
-        string = Conversions.StringValue(string)
-    if type(start) is not types.FloatType:
+    if not isinstance(st, XPathStringType):
+        st = Conversions.StringValue(st)
+    if not isinstance(start, NumberType):
         start = Conversions.NumberValue(start)
 
-    # NaN and +Inf indicate no substring
-    if number.isnan(start) or (number.isinf(start) and start > 0):
+    # start == NaN: spec doesn't say; assume no substring to return
+    # start == +Inf or -Inf: no substring to return
+    if number.isnan(start) or number.isinf(start):
         return u''
 
+    # start is finite, safe for int() and round().
+    start = int(round(start))
+    # convert to 0-based index for python string slice
     if start < 1:
-        # This handles -Inf which explodes int()
-        start = 0
+        startidx = 0
     else:
-        # start is guaranteed to be at least 1
-        # convert to python (0-based) index
-        start = int(round(start)) - 1
+        startidx = start - 1
 
+    # length undefined: return chars startidx to end
     if length is None:
-        return string[start:]
-    elif type(length) is not types.FloatType:
+        return st[startidx:]
+    elif not isinstance(length, NumberType):
         length = Conversions.NumberValue(length)
+
+    # length == NaN: spec doesn't say; assume no substring to return
     if number.isnan(length):
         return u''
+    # length == +Inf: return chars startidx to end
+    # length == -Inf: no substring to return
+    elif number.isinf(length):
+        if length > 0:
+            return st[startidx:]
+        else:
+            return u''
+
+    # length is finite, safe for int() and round().
     length = int(round(length))
-    if length <= 0:
+
+    # return value must end before position (start+length)
+    # which is (start+length-1) in 0-based index
+    endidx = start + length - 1
+    if endidx > startidx:
+        return st[startidx:endidx]
+    else:
         return u''
-    return string[start:start + length]
 
 
@@ -250,5 +251,7 @@
     if st is None:
         st = context.node
-    return len(Conversions.StringValue(st))
+    if not isinstance(st, XPathStringType):
+        st = Conversions.StringValue(st)
+    return float(len(st))
 
 
@@ -257,15 +260,21 @@
     if st is None:
         st = context.node
-    st = Conversions.StringValue(st)
-    return ' '.join(st.split())
+    if not isinstance(st, XPathStringType):
+        st = Conversions.StringValue(st)
+    return u' '.join(st.split())
 
 
 def Translate(context, source, fromChars, toChars):
     """Function: <string> translate(<string>, <string>, <string>)"""
-    source = Conversions.StringValue(source)
-    fromChars = Conversions.StringValue(fromChars)
+    if not isinstance(source, XPathStringType):
+        source = Conversions.StringValue(source)
+    if not isinstance(fromChars, XPathStringType):
+        fromChars = Conversions.StringValue(fromChars)
+    if not isinstance(toChars, XPathStringType):
+        toChars = Conversions.StringValue(toChars)
+
     # remove duplicate chars from From string
     fromChars = reduce(lambda st, c: st + c * (st.find(c) == -1), fromChars, '')
-    toChars = Conversions.StringValue(toChars)[:len(fromChars)]
+    toChars = toChars[:len(fromChars)]
 
     # string.maketrans/translate do not handle unicode
@@ -281,12 +290,13 @@
 ### Boolean Functions ###
 
-def Boolean(context, object):
+def Boolean(context, object_):
     """Function: <boolean> boolean(<object>)"""
-    return Conversions.BooleanValue(object)
+    return Conversions.BooleanValue(object_)
 
 
-def Not(context, object):
+def Not(context, object_):
     """Function: <boolean> not(<boolean>)"""
-    return (not Conversions.BooleanValue(object) and boolean.true) or boolean.false
+    return ((not Conversions.BooleanValue(object_) and boolean.true)
+            or boolean.false)
 
 
@@ -303,39 +313,51 @@
 def Lang(context, lang):
     """Function: <boolean> lang(<string>)"""
-    lang = Conversions.StringValue(lang).upper()
+    lang = Conversions.StringValue(lang).lower()
     node = context.node
-    while node:
-        lang_attr = filter(lambda x:x.name == 'xml:lang' and x.value, node.attributes.values())
-        value = lang_attr and lang_attr[0].nodeValue or None
-        if value:
-            # See if there is a suffix
-            index = value.find('-')
-            if index != -1:
-                value = value[:index]
-            value = value.upper()
-            return value == lang and boolean.true or boolean.false
-        node = node.nodeType == Node.ATTRIBUTE_NODE and node.ownerElement or node.parentNode
-        if node.nodeType == Node.DOCUMENT_NODE:
-            break
+    while node.parentNode:
+        for attr in node.attributes.values():
+            # Search for xml:lang attribute
+            if (attr.localName == 'lang' and
+                attr.namespaceURI == XML_NAMESPACE):
+                value = attr.nodeValue.lower()
+                # Exact match (PrimaryPart and possible SubPart)
+                if value == lang:
+                    return boolean.true
+
+                # Just PrimaryPart (ignore '-' SubPart)
+                index = value.find('-')
+                if index != -1 and value[:index] == lang:
+                    return boolean.true
+
+                # Language doesn't match
+                return boolean.false
+
+        # Continue to next ancestor
+        node = node.parentNode
+
+    # No xml:lang declarations found
     return boolean.false
 
 ### Number Functions ###
 
-def Number(context, object=None):
+def Number(context, object_=None):
     """Function: <number> number(<object>?)"""
-    if object is None:
-        object = [context.node]
-    return Conversions.NumberValue(object)
+    if object_ is None:
+        object_ = [context.node]
+    return Conversions.NumberValue(object_)
 
 
 def Sum(context, nodeSet):
     """Function: <number> sum(<node-set>)"""
+    if not isinstance(nodeSet, NodesetType):
+        raise RuntimeException(RuntimeException.WRONG_ARGUMENTS, 'sum',
+                               _("expected node-set argument"))
     nns = map(Conversions.NumberValue, nodeSet)
     return reduce(lambda x, y: x + y, nns, 0)
 
 
-def Floor(context, object):
+def Floor(context, object_):
     """Function: <number> floor(<number>)"""
-    num = Conversions.NumberValue(object)
+    num = Conversions.NumberValue(object_)
     if number.isnan(num) or number.isinf(num):
         return num
@@ -343,12 +365,12 @@
         return num
     elif num < 0:
-        return int(num) - 1
+        return float(int(num) - 1)
     else:
-        return int(num)
+        return float(int(num))
 
 
-def Ceiling(context, object):
+def Ceiling(context, object_):
     """Function: <number> ceiling(<number>)"""
-    num = Conversions.NumberValue(object)
+    num = Conversions.NumberValue(object_)
     if number.isnan(num) or number.isinf(num):
         return num
@@ -356,14 +378,16 @@
         return num
     elif num > 0:
-        return int(num) + 1
+        return float(int(num) + 1)
     else:
-        return int(num)
+        return float(int(num))
 
 
-def Round(context, object):
+def Round(context, object_):
     """Function: <number> round(<number>)"""
-    num = Conversions.NumberValue(object)
+    num = Conversions.NumberValue(object_)
     if number.isnan(num) or number.isinf(num):
         return num
+    elif num < 0 and num % 1.0 == 0.5:
+        return round(num, 0) + 1
     else:
         return round(num, 0)
@@ -402,5 +426,2 @@
     }
 
-Args = {
-    Substring : (Types.StringType, [Types.StringType, Types.StringType]),
-    }
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/MathFunctions.py.diff?r1=1.4&r2=1.4.6.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/MathFunctions.py?rev=1.4.6.1&content-type=text/vnd.viewcvs-markup

Index: MathFunctions.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/MathFunctions.py,v
retrieving revision 1.4
retrieving revision 1.4.6.1
diff -U2 -r1.4 -r1.4.6.1
--- MathFunctions.py	26 Aug 2002 17:40:43 -0000	1.4
+++ MathFunctions.py	4 Dec 2006 07:06:59 -0000	1.4.6.1
@@ -1,20 +1,16 @@
 ########################################################################
-#
-# File Name:   MathFunctions.py
-#
+# $Header$
 """
 4XPath-specific math extension functions
-WWW: http://4suite.org        e-mail: support at 4suite.org
 
-Copyright 2000-2002 Fourthought Inc, USA.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-import math, types
-import whrandom
-from xml.dom import Node
-from Ft.Lib import boolean
-from Ft.Lib import Uri
+import math
+
 from Ft.Xml.XPath import Conversions, FT_EXT_NAMESPACE
+from Ft.Xml.XPath import XPathTypes as Types
 
 
@@ -22,12 +18,21 @@
     "math.sin"
     return math.sin(Conversions.NumberValue(x))
+Sin.arguments = (Types.NumberType,)
+Sin.result = Types.NumberType
+
 
 def Cos(context, x):
     "math.cos"
     return math.cos(Conversions.NumberValue(x))
+Cos.arguments = (Types.NumberType,)
+Cos.result = Types.NumberType
+
 
 def DegreesToRads(context, x):
     "Convert degrees to radians"
     return Conversions.NumberValue(x)/180*math.pi
+DegreesToRads.arguments = (Types.NumberType,)
+DegreesToRads.result = Types.NumberType
+
 
 def Fact(context, x):
@@ -35,6 +40,8 @@
     x = Conversions.NumberValue(x)
     if x > 1:
-        return reduce(lambda x,y:x*y,range(1,x+1),1)
+        return reduce(lambda x,y: x*y, xrange(1,x+1), 1)
     return 1
+Fact.arguments = (Types.NumberType,)
+Fact.result = Types.NumberType
 
 
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/MessageSource.py.diff?r1=1.3&r2=1.3.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/MessageSource.py?rev=1.3.2.1&content-type=text/vnd.viewcvs-markup

Index: MessageSource.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/MessageSource.py,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -U2 -r1.3 -r1.3.2.1
--- MessageSource.py	19 Jan 2003 04:39:43 -0000	1.3
+++ MessageSource.py	4 Dec 2006 07:06:59 -0000	1.3.2.1
@@ -1,26 +1,45 @@
-from Ft.Xml.XPath import RuntimeException, CompiletimeException
-
-try:
-    import os, gettext
-    locale_dir = os.path.split(__file__)[0]
-    gettext.install('4Suite', locale_dir)
-#except ImportError, IOError:
-#Note, 1.5.2 has gettext, but no install
-except (ImportError, AttributeError, IOError):
-    def _(msg):
-        return msg
-
-COMPILETIME = {
-    CompiletimeException.INTERNAL: _('There is an internal bug in 4XPath.  Please report this error code to support at 4suite.org: %s'),
-    CompiletimeException.SYNTAX: _('XPath Parse error at line %d, column %d: %s'),
-    CompiletimeException.PROCESSING: _('Error evaluating XPath expression.'),
-    #CompiletimeException.: _(''),
-    }
-
-RUNTIME = {
-    RuntimeException.INTERNAL: _('There is an internal bug in 4XPath.  Please report this error code to support at 4suite.org: %s'),
+########################################################################
+# $Header$
+"""
+XPath error codes and messages
+
+Copyright 2003 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
+"""
+
+from Ft import TranslateMessage as _
+
+from Ft.Xml.XPath import CompiletimeException, RuntimeException
+
+# messages for expression compile-time errors
+ERROR_COMPILETIME = {
+    # internal/unexpected errors
+    CompiletimeException.INTERNAL: _('There is an internal bug in 4XPath. '
+        'Please make a post to the 4Suite mailing list to report this error '
+        'message to the developers. Include platform details and info about '
+        'how to reproduce the error. Info about the mailing list is at '
+        'http://lists.fourthought.com/mailman/listinfo/4suite. '
+        'The error code to report is: %s'),
+    # other compile-time errors
+    CompiletimeException.SYNTAX: _('XPath expression syntax error at line %d, column %d: %s'),
+}
+
+
+# messages for expression evaluation (run-time) errors
+ERROR_RUNTIME = {
+    # internal/unexpected errors
+    RuntimeException.INTERNAL: _('There is an internal bug in 4XPath. '
+        'Please make a post to the 4Suite mailing list to report this error '
+        'message to the developers. Include platform details and info about '
+        'how to reproduce the error. Info about the mailing list is at '
+        'http://lists.fourthought.com/mailman/listinfo/4suite. '
+        'The error code to report is: %s'),
 
+    # other runtime errors
     RuntimeException.NO_CONTEXT: _('An XPath Context object is required in order to evaluate an expression.'),
-    RuntimeException.UNDEFINED_VARIABLE: _('Variable undefined: ("%s", "%s").'),
+
+    RuntimeException.UNDEFINED_VARIABLE: _(
+        "Variable '%(name)s' not declared"),
     RuntimeException.UNDEFINED_PREFIX: _('Undefined namespace prefix: "%s".'),
     RuntimeException.UNDEFINED_FUNCTION: _('Undefined function: "%s".'),
@@ -31,6 +50,3 @@
     RuntimeException.ARGCOUNT_EXACT : _('%s() takes exactly %d arguments (%d given)'),
     RuntimeException.ARGCOUNT_ATMOST : _('%s() takes at most %d arguments (%d given)'),
-    
-    #RuntimeException.: _(''),
-    }
-
+}
--- NamespaceNode.py DELETED ---
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedAbbreviatedAbsoluteLocationPath.py.diff?r1=1.5.2.2&r2=1.5.2.3
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedAbbreviatedAbsoluteLocationPath.py?rev=1.5.2.3&content-type=text/vnd.viewcvs-markup

Index: ParsedAbbreviatedAbsoluteLocationPath.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedAbbreviatedAbsoluteLocationPath.py,v
retrieving revision 1.5.2.2
retrieving revision 1.5.2.3
diff -U2 -r1.5.2.2 -r1.5.2.3
--- ParsedAbbreviatedAbsoluteLocationPath.py	3 Apr 2003 14:58:13 -0000	1.5.2.2
+++ ParsedAbbreviatedAbsoluteLocationPath.py	4 Dec 2006 07:06:59 -0000	1.5.2.3
@@ -1,18 +1,17 @@
 ########################################################################
-#
-# File Name:   ParsedAbbreviatedAbsoluteLocationPath.py
-#
-# Docs:        http://docs.4suite.org/XPATH/ParsedAbbreviatedAbsoluteLocationPath.py.html
-#
+# $Header$
 """
-A parsed token for an abreviated absolute location path.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+A parsed token that represents an abbreviated absolute location path.
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
 from xml.dom import Node
-from Ft.Xml.XPath import Util, NOLIMIT
+
+from Ft.Lib.Set import Unique
+from Ft.Xml.XPath import NOLIMIT
+
 
 class ParsedAbbreviatedAbsoluteLocationPath:
@@ -29,5 +28,5 @@
         for child in context.node.childNodes:
             context.node = child
-            if checklimit: 
+            if checklimit:
                 results = self._rel.select(context, limit - found)
                 found += len(results)
@@ -36,9 +35,9 @@
             # Ensure no duplicates
             #FIXME: propagate forwardsOnly cheeck to this class, an you can elminate this dupe checking for the 80%+ case
-            nodeset.extend(filter(lambda n, s=nodeset: n not in s, results))
+            nodeset.extend([ n for n in results if n not in nodeset ])
             if child.nodeType == Node.ELEMENT_NODE:
-                if checklimit: 
-                    if found < limit: 
-                        found += self._descendants(context, nodeset, limit - found) 
+                if checklimit:
+                    if found < limit:
+                        found += self._descendants(context, nodeset, limit - found)
                 else:
                     self._descendants(context, nodeset)
@@ -52,6 +51,5 @@
 
         # Start at the document node
-        if context.node.ownerDocument:
-            context.node = context.node.ownerDocument
+        context.node = context.node.rootNode
 
         nodeset = self._rel.select(context, limit)
@@ -62,5 +60,5 @@
             return nodeset
         else:
-            return Util.SortDocOrder(context, nodeset)
+            return Unique(nodeset)
     select = evaluate
 
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedAbbreviatedRelativeLocationPath.py.diff?r1=1.3.2.2&r2=1.3.2.3
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedAbbreviatedRelativeLocationPath.py?rev=1.3.2.3&content-type=text/vnd.viewcvs-markup

Index: ParsedAbbreviatedRelativeLocationPath.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedAbbreviatedRelativeLocationPath.py,v
retrieving revision 1.3.2.2
retrieving revision 1.3.2.3
diff -U2 -r1.3.2.2 -r1.3.2.3
--- ParsedAbbreviatedRelativeLocationPath.py	3 Apr 2003 14:58:13 -0000	1.3.2.2
+++ ParsedAbbreviatedRelativeLocationPath.py	4 Dec 2006 07:06:59 -0000	1.3.2.3
@@ -4,15 +4,12 @@
 A parsed token that represents a abbreviated relative location path.
 
-Copyright 2003 Fourthought, Inc. (USA).
+Copyright 2005 Fourthought, Inc. (USA).
 Detailed license and copyright information: http://4suite.org/COPYRIGHT
 Project home, documentation, distributions: http://4suite.org/
 """
 
-from Ft.Xml.XPath import ParsedNodeTest
-from Ft.Xml.XPath import ParsedPredicateList
-from Ft.Xml.XPath import ParsedAxisSpecifier
-from Ft.Xml.XPath import ParsedStep, NOLIMIT
-
-from Ft.Lib import Set
+from xml.dom import Node
+from Ft.Lib.Set import Unique
+from Ft.Xml.XPath import NOLIMIT, XPathTypes as Types
 
 class ParsedAbbreviatedRelativeLocationPath:
@@ -24,38 +21,48 @@
         self._left = left
         self._right = right
-        nt = ParsedNodeTest.ParsedNodeTest('node', '')
-        ppl = ParsedPredicateList.ParsedPredicateList([])
-        as = ParsedAxisSpecifier.ParsedAxisSpecifier('descendant-or-self')
-        self._middle = ParsedStep.ParsedStep(as, nt, ppl)
         return
 
+    def _descendants(self, context, nodeset):
+        for child in context.node.childNodes:
+            context.node = child
+            results = self._right.select(context)
+            if not isinstance(results, Types.NodesetType):
+                raise TypeError("%r must be a node-set, not a %s" % (
+                    self._right,
+                    Types.g_xpathPrimitiveTypes.get(type(results),
+                                                    type(results).__name__)))
+            if results:
+                nodeset.extend(results)
+            if child.nodeType == Node.ELEMENT_NODE:
+                nodeset = self._descendants(context, nodeset)
+        return nodeset
+
     def evaluate(self, context, limit=NOLIMIT):
-        nodeset = self._left.select(context)
+        """Returns a node-set"""
+        left = self._left.select(context)
+        if not isinstance(left, Types.NodesetType):
+            raise TypeError("%r must be a node-set, not a %s" % (
+                self._left,
+                Types.g_xpathPrimitiveTypes.get(type(left),
+                                                type(left).__name__)))
 
         state = context.copy()
 
-        size = len(nodeset)
-        result = []
-        for pos in range(size):
-            context.node, context.position, context.size = \
-                          nodeset[pos], pos + 1, size
-            subRt = self._middle.select(context, limit)
-            if self._middle.isForwardsOnly:
-                #Then we cannot have dupes from subRt
-                result.extend(subRt)
-            else:
-                result = Set.Union(result, subRt)
-
-        nodeset = result
-        size = len(nodeset)
-        result = []
-        for pos in range(size):
-            context.node, context.position, context.size = \
-                          nodeset[pos], pos + 1, size
-            subRt = self._right.select(context)
-            result = Set.Union(result, subRt)
+        results = []
+        for node in left:
+            context.node = node
+            nodeset = self._right.select(context)
+            if not isinstance(nodeset, Types.NodesetType):
+                raise TypeError("%r must be a node-set, not a %s" % (
+                    self._right,
+                    Types.g_xpathPrimitiveTypes.get(type(nodeset),
+                                                    type(nodeset).__name__)))
+            results.extend(self._descendants(context, nodeset))
+
+        results = Unique(results)
 
         context.set(state)
-        return result
+        return results
+
     select = evaluate
 
@@ -63,5 +70,4 @@
         print indent + str(self)
         self._left.pprint(indent + '  ')
-        self._middle.pprint(indent + '  ')
         self._right.pprint(indent + '  ')
 
@@ -71,5 +77,5 @@
             repr(self),
             )
-    
+
     def __repr__(self):
         return repr(self._left) + '//' + repr(self._right)
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedAxisSpecifier.py.diff?r1=1.11.2.2&r2=1.11.2.3
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedAxisSpecifier.py?rev=1.11.2.3&content-type=text/vnd.viewcvs-markup

Index: ParsedAxisSpecifier.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedAxisSpecifier.py,v
retrieving revision 1.11.2.2
retrieving revision 1.11.2.3
diff -U2 -r1.11.2.2 -r1.11.2.3
--- ParsedAxisSpecifier.py	3 Apr 2003 14:58:13 -0000	1.11.2.2
+++ ParsedAxisSpecifier.py	4 Dec 2006 07:06:59 -0000	1.11.2.3
@@ -1,27 +1,16 @@
 ########################################################################
-#
-# File Name:   ParsedAxisSpecifier.py
-#
-# Docs:        http://docs.4suite.org/XPATH/ParsedAxisSpecifier.py.html
-#
+# $Header$
 """
-A Parsed token that represents an acis specifier on the parsed tree.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+A parsed token that represents an axis specifier.
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2004 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
 from xml.dom import Node
-from Ft.Xml import XMLNS_NAMESPACE
-from Ft.Xml.XPath import g_xpathRecognizedNodes
-from Ft.Xml.XPath import NAMESPACE_NODE
-from Ft.Xml.XPath import NOLIMIT
-#from Ft.Xml.XPath import Util
-from Ft.Xml.XPath import NamespaceNode
 
-from Ft.Xml.Domlette import GetAllNs
+from Ft.Xml.XPath import NAMESPACE_NODE, NOLIMIT
 
-import string
 
 def ParsedAxisSpecifier(axis):
@@ -31,4 +20,5 @@
         raise SyntaxError("Invalid axis: %s" % axis)
 
+
 class AxisSpecifier:
 
@@ -110,12 +100,7 @@
     def select(self, context, nodeTest, limit=NOLIMIT):
         """Select all of the attributes from the context node"""
-        if context.node.nodeType != Node.ELEMENT_NODE: return ([],0)
-        attrs = filter(lambda attr:
-                       attr.namespaceURI != XMLNS_NAMESPACE,
-                       context.node.attributes.values())
-        rt = filter(lambda attr, test=nodeTest, context=context, pt=self.principalType:
-                    test(context, attr, pt),
-                    attrs)
-        return (rt, 0)
+        result = [ attr for attr in context.node.xpathAttributes
+                   if nodeTest(context, attr, self.principalType) ]
+        return (result, 0)
 
 
@@ -124,15 +109,13 @@
     def select(self, context, nodeTest, limit=NOLIMIT):
         """Select all of the children of the context node"""
-        rt = []
-        if context.node.nodeType != Node.ATTRIBUTE_NODE:
-            #Optimize the common limit=1 case
-            if limit == 1:
-                for node in (context.node.childNodes or []):
-                    if nodeTest(context, node, self.principalType):
-                        return ([node], 0)
-            else:
-                rt = [ node for node in (context.node.childNodes or [])
-                            if nodeTest(context, node, self.principalType) ]
-        return (rt, 0)
+        #Optimize the common limit=1 case
+        if limit == 1:
+            for node in context.node.childNodes:
+                if nodeTest(context, node, self.principalType):
+                    return ([node], 0)
+        else:
+            result = [ node for node in context.node.childNodes
+                       if nodeTest(context, node, self.principalType) ]
+        return (result, 0)
 
 
@@ -174,5 +157,5 @@
 class ParsedFollowingAxisSpecifier(AxisSpecifier):
 
-    def select(self,context, nodeTest):
+    def select(self, context, nodeTest, limit=NOLIMIT):
         """
         Select all of the nodes the follow the context node,
@@ -199,15 +182,7 @@
 
     def select(self, context, nodeTest, limit=NOLIMIT):
-        """Select all of the namespaces from the context"""
-        if context.node.nodeType != Node.ELEMENT_NODE:
-            return ([], 0)
-        result = []
-        nss = GetAllNs(context.node)
-        for prefix in nss.keys():
-            nsNode = NamespaceNode.NamespaceNode(prefix, nss[prefix],
-                                                 context.node,
-                                                 context.node.rootNode)
-            if nodeTest(context, nsNode, self.principalType):
-                result.append(nsNode)
+        """Select all of the namespaces from the context node."""
+        result = [ xns for xns in context.node.xpathNamespaces
+                   if nodeTest(context, xns, self.principalType) ]
         return (result, 0)
 
@@ -262,5 +237,5 @@
         # Create a single list in document order
         result = []
-        for i in range(1, len(doc_list)+1):
+        for i in xrange(1, len(doc_list)+1):
             result.extend(doc_list[-i])
         return (result, 1)
@@ -275,4 +250,5 @@
         return ([], 0)
 
+
 g_classMap = {
     'ancestor' : ParsedAncestorAxisSpecifier,
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedExpr.py.diff?r1=1.25.2.3&r2=1.25.2.4
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedExpr.py?rev=1.25.2.4&content-type=text/vnd.viewcvs-markup

Index: ParsedExpr.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedExpr.py,v
retrieving revision 1.25.2.3
retrieving revision 1.25.2.4
diff -U2 -r1.25.2.3 -r1.25.2.4
--- ParsedExpr.py	3 Apr 2003 14:58:13 -0000	1.25.2.3
+++ ParsedExpr.py	4 Dec 2006 07:06:59 -0000	1.25.2.4
@@ -1,30 +1,30 @@
 ########################################################################
-#
-# File Name:   ParsedExpr.py
-#
-# Docs:        http://docs.4suite.org/XPATH/ParsedExpr.py.html
-#
+# $Header$
 """
-The implementation of all of the expression pared tokens.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+The implementation of parsed XPath expression tokens.
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-import types, operator, inspect
+import types, inspect
+from xml.dom import Node
 
-from Ft.Xml import EMPTY_NAMESPACE
 from Ft.Lib import boolean, number
-from Ft.Lib import Set
-from Ft.Xml import SplitQName
-from Ft.Xml.XPath import CompiletimeException, RuntimeException
+from Ft.Lib.Set import Union, Unique
+from Ft.Xml import EMPTY_NAMESPACE
+from Ft.Xml.Lib.XmlString import SplitQName, XmlStrStrip
+from Ft.Xml.XPath import RuntimeException, NOLIMIT
 from Ft.Xml.XPath import ParsedStep, ParsedAxisSpecifier, ParsedNodeTest
-from Ft.Xml.XPath import Conversions, Util, Types
-from Ft.Xml.Domlette import XmlStrStrip
-from Ft.Xml.XPath import NOLIMIT
+from Ft.Xml.XPath import Conversions, _comparisons
+from Ft.Xml.XPath import XPathTypes as Types
 
 
 class ParsedLiteralExpr:
+    """
+    An object representing a string literal expression
+    (XPath 1.0 grammar production 29: Literal)
+    """
     def __init__(self, literal):
         if len(literal) >= 2 and (literal[0] in ['\'', '"'] and
@@ -43,8 +43,12 @@
 
     def __repr__(self):
-        return '"' + self._literal + '"'
+        return '"' + self._literal.encode('unicode_escape') + '"'
 
 
 class ParsedNLiteralExpr(ParsedLiteralExpr):
+    """
+    An object representing a numeric literal expression
+    (XPath 1.0 grammar production 30: Number)
+    """
     def __init__(self, nliteral):
         self._nliteral = nliteral
@@ -58,7 +62,19 @@
 
     def __repr__(self):
-        return str(self._nliteral)
+        if number.isnan(self._literal):
+            return 'NaN'
+        elif number.isinf(self._literal):
+            if self._literal < 0:
+                return '-Infinity'
+            else:
+                return 'Infinity'
+        else:
+            return str(self._nliteral)
 
 class ParsedVariableReferenceExpr:
+    """
+    An object representing a variable reference expression
+    (XPath 1.0 grammar production 36: VariableReference)
+    """
     def __init__(self,name):
         self._name = name
@@ -81,5 +97,5 @@
         except KeyError:
             raise RuntimeException(RuntimeException.UNDEFINED_VARIABLE,
-                                   expanded[0], expanded[1])
+                                   name=self._name, key=self._key)
 
     def pprint(self, indent=''):
@@ -94,19 +110,28 @@
 
 def ParsedFunctionCallExpr(name, args):
+    """
+    Returns an object representing a function call expression
+    (XPath 1.0 grammar production 16: FunctionCall)
+    """
     name = XmlStrStrip(name)
     key = SplitQName(name)
-    count = len(args)
-    if count == 0:
+    if not args:
         return FunctionCall(name, key, args)
+    count = len(args)
     if count == 1:
         return FunctionCall1(name, key, args)
-    if count == 2:
+    elif count == 2:
         return FunctionCall2(name, key, args)
-    if count == 3:
+    elif count == 3:
         return FunctionCall3(name, key, args)
-    return FunctionCallN(name, key, args)
+    else:
+        return FunctionCallN(name, key, args)
 
 
 class FunctionCall:
+    """
+    An object representing a function call expression
+    (XPath 1.0 grammar production 16: FunctionCall)
+    """
     def __init__(self, name, key, args):
         self._name = name
@@ -159,6 +184,7 @@
 
     def evaluate(self, context, limit=NOLIMIT):
-        """Call the function"""
-        if not self._func:
+        """Returns the result of calling the function"""
+        func = self._func
+        if func is None:
             (prefix, local) = self._key
             if prefix:
@@ -169,7 +195,9 @@
             else:
                 expanded = self._key
-            self._func = context.functions.get(expanded, self.error)
+            func = context.functions.get(expanded, self.error)
+            if not ('nocache' in func.__dict__ and func.nocache):
+                self._func = func
         try:
-            result = self._func(context)
+            result = func(context)
         except TypeError:
             exception = self.getArgumentError()
@@ -179,4 +207,8 @@
             raise exception
 
+        #Expensive assert contributed by Adam Souzis.
+        #No effect on Python running in optimized mode,
+        #But would mean significant slowdown for developers, so disabled by default
+        #assert not isinstance(result, list) or len(result) == len(Set.Unique(result))
         return result
 
@@ -202,4 +234,5 @@
 
 class FunctionCall1(FunctionCall):
+    # a function call with 1 argument
     def __init__(self, name, key, args):
         FunctionCall.__init__(self, name, key, args)
@@ -208,5 +241,6 @@
     def evaluate(self, context, limit=NOLIMIT):
         arg0 = self._arg0.evaluate(context)
-        if not self._func:
+        func = self._func
+        if func is None:
             (prefix, local) = self._key
             if prefix:
@@ -217,7 +251,9 @@
             else:
                 expanded = self._key
-            self._func = context.functions.get(expanded, self.error)
+            func = context.functions.get(expanded, self.error)
+            if not ('nocache' in func.__dict__ and func.nocache):
+                self._func = func
         try:
-            result = self._func(context, arg0)
+            result = func(context, arg0)
         except TypeError:
             exception = self.getArgumentError()
@@ -227,8 +263,13 @@
             raise exception
 
+        #Expensive assert contributed by Adam Souzis.
+        #No effect on Python running in optimized mode,
+        #But would mean significant slowdown for developers, so disabled by default
+        #assert not isinstance(result, list) or len(result) == len(Set.Unique(result))
         return result
 
 
 class FunctionCall2(FunctionCall):
+    # a function call with 2 arguments
     def __init__(self, name, key, args):
         FunctionCall.__init__(self, name, key, args)
@@ -239,5 +280,6 @@
         arg0 = self._arg0.evaluate(context)
         arg1 = self._arg1.evaluate(context)
-        if not self._func:
+        func = self._func
+        if func is None:
             (prefix, local) = self._key
             if prefix:
@@ -248,7 +290,9 @@
             else:
                 expanded = self._key
-            self._func = context.functions.get(expanded, self.error)
+            func = context.functions.get(expanded, self.error)
+            if not ('nocache' in func.__dict__ and func.nocache):
+                self._func = func
         try:
-            result = self._func(context, arg0, arg1)
+            result = func(context, arg0, arg1)
         except TypeError:
             exception = self.getArgumentError()
@@ -258,8 +302,13 @@
             raise exception
 
+        #Expensive assert contributed by Adam Souzis.
+        #No effect on Python running in optimized mode,
+        #But would mean significant slowdown for developers, so disabled by default
+        #assert not isinstance(result, list) or len(result) == len(Set.Unique(result))
         return result
 
 
 class FunctionCall3(FunctionCall):
+    # a function call with 3 arguments
     def __init__(self, name, key, args):
         FunctionCall.__init__(self, name, key, args)
@@ -272,5 +321,6 @@
         arg1 = self._arg1.evaluate(context)
         arg2 = self._arg2.evaluate(context)
-        if not self._func:
+        func = self._func
+        if func is None:
             (prefix, local) = self._key
             if prefix:
@@ -281,7 +331,9 @@
             else:
                 expanded = self._key
-            self._func = context.functions.get(expanded, self.error)
+            func = context.functions.get(expanded, self.error)
+            if not ('nocache' in func.__dict__ and func.nocache):
+                self._func = func
         try:
-            result = self._func(context, arg0, arg1, arg2)
+            result = func(context, arg0, arg1, arg2)
         except TypeError:
             exception = self.getArgumentError()
@@ -291,8 +343,13 @@
             raise exception
 
+        #Expensive assert contributed by Adam Souzis.
+        #No effect on Python running in optimized mode,
+        #But would mean significant slowdown for developers, so disabled by default
+        #assert not isinstance(result, list) or len(result) == len(Set.Unique(result))
         return result
 
 
 class FunctionCallN(FunctionCall):
+    # a function call with more than 3 arguments
     def __init__(self, name, key, args):
         FunctionCall.__init__(self, name, key, args)
@@ -300,5 +357,6 @@
     def evaluate(self, context, limit=NOLIMIT):
         args = map(lambda arg, c=context: arg.evaluate(c), self._args)
-        if not self._func:
+        func = self._func
+        if func is None:
             (prefix, local) = self._key
             if prefix:
@@ -309,7 +367,9 @@
             else:
                 expanded = self._key
-            self._func = context.functions.get(expanded, self.error)
+            func = context.functions.get(expanded, self.error)
+            if not ('nocache' in func.__dict__ and func.nocache):
+                self._func = func
         try:
-            result = self._func(context, *args)
+            result = func(context, *args)
         except TypeError:
             exception = self.getArgumentError()
@@ -319,4 +379,8 @@
             raise exception
 
+        #Expensive assert contributed by Adam Souzis.
+        #No effect on Python running in optimized mode,
+        #But would mean significant slowdown for developers, so disabled by default
+        #assert not isinstance(result, list) or len(result) == len(Set.Unique(result))
         return result
 
@@ -327,4 +391,8 @@
 
 class ParsedUnionExpr:
+    """
+    An object representing a union expression
+    (XPath 1.0 grammar production 18: UnionExpr)
+    """
     def __init__(self,left,right):
         self._left = left
@@ -337,14 +405,19 @@
 
     def evaluate(self, context, limit=NOLIMIT):
+        """Returns a node-set"""
         left = self._left.evaluate(context)
         if not isinstance(left, Types.NodesetType):
-            raise TypeError("%s must be node-set, not %s" % (repr(left), type(left).__name__))
+            raise TypeError("%s must be a node-set, not a %s" % (repr(self._left),
+                            Types.g_xpathPrimitiveTypes.get(type(left),
+                            type(left).__name__)))
 
         right = self._right.evaluate(context)
         if not isinstance(right, Types.NodesetType):
-            raise TypeError("%s must be node-set, not %s" % (repr(right), type(right).__name__))
+            raise TypeError("%s must be a node-set, not a %s" % (repr(self._right),
+                            Types.g_xpathPrimitiveTypes.get(type(right),
+                            type(right).__name__)))
 
-        set = Set.Union(left, right)
-        return Util.SortDocOrder(context, set)
+        set = Union(left, right)
+        return set
 
     def __str__(self):
@@ -356,15 +429,13 @@
 
 class ParsedPathExpr:
+    """
+    An object representing a path expression
+    (XPath 1.0 grammar production 19: PathExpr)
+    """
     def __init__(self, descendant, left, right):
+        self._descendant = descendant
         self._left = left
         self._right = right
-        if descendant:
-            nt = ParsedNodeTest.ParsedNodeTest('node', '')
-            axis = ParsedAxisSpecifier.ParsedAxisSpecifier('descendant-or-self')
-            from Ft.Xml.XPath import ParsedPredicateList
-            pList = ParsedPredicateList.ParsedPredicateList([])
-            self._step = ParsedStep.ParsedStep(axis, nt, pList)
-        else:
-            self._step = None
+        return
 
     def pprint(self, indent=''):
@@ -373,35 +444,49 @@
         self._right.pprint(indent + '  ')
 
-    def evaluate(self, context, limit=NOLIMIT):
-        """Evaluate the left, then if op =// the parsedStep, then the right, push context each time"""
-        """Returns a node set"""
+    def _descendants(self, context, nodeset):
+        for child in context.node.childNodes:
+            context.node = child
+            results = self._right.select(context)
+            if not isinstance(results, Types.NodesetType):
+                raise TypeError("%r must be a node-set, not a %s" % (
+                    self._right,
+                    Types.g_xpathPrimitiveTypes.get(type(results),
+                                                    type(results).__name__)))
+            if results:
+                nodeset.extend(results)
+            if child.nodeType == Node.ELEMENT_NODE:
+                nodeset = self._descendants(context, nodeset)
+        return nodeset
 
-        nodeset = self._left.evaluate(context)
-        if not isinstance(nodeset, Types.NodesetType):
-            raise TypeError("%s must be node-set, not %s" % (repr(self._left), type(nodeset).__name__))
+    def evaluate(self, context, limit=NOLIMIT):
+        """Returns a node-set"""
+        #Evaluate the left, then, if op =//, the parsedStep.
+        #Then evaluate the right, pushing the context each time.
+        left = self._left.evaluate(context)
+        if not isinstance(left, Types.NodesetType):
+            raise TypeError("%r must be a node-set, not a %s" % (
+                self._left,
+                Types.g_xpathPrimitiveTypes.get(type(left),
+                                                type(left).__name__)))
 
         state = context.copy()
-        if self._step:
-            res = []
-            size = len(nodeset)
-            for pos in range(size):
-                context.node, context.position, context.size = \
-                              nodeset[pos], pos + 1, size
-                subRt = self._step.select(context)
-                res = Set.Union(res,subRt)
-            nodeset = res
-
-        res = []
-        size = len(nodeset)
-        for pos in range(size):
-            context.node, context.position, context.size = \
-                          nodeset[pos], pos + 1, size
-            subRt = self._right.select(context)
-            if not isinstance(subRt, Types.NodesetType):
-                raise TypeError("%s must be node-set, not %s" % (repr(subRt), type(subRt).__name__))
-            res = Set.Union(res,subRt)
+
+        results = []
+        for node in left:
+            context.node = node
+            nodeset = self._right.select(context)
+            if not isinstance(nodeset, Types.NodesetType):
+                raise TypeError("%r must be a node-set, not a %s" % (
+                    self._right,
+                    Types.g_xpathPrimitiveTypes.get(type(nodeset),
+                                                    type(nodeset).__name__)))
+            elif self._descendant:
+                nodeset = self._descendants(context, nodeset)
+            results.extend(nodeset)
+
+        results = Unique(results)
 
         context.set(state)
-        return res
+        return results
 
     def __str__(self):
@@ -409,22 +494,26 @@
 
     def __repr__(self):
-        op = self._step and '//' or '/'
+        op = self._descendant and '//' or '/'
         return repr(self._left) + op + repr(self._right)
 
 
 class ParsedFilterExpr:
-    def __init__(self, filter, predicates):
-        self._filter = filter
+    """
+    An object representing a filter expression
+    (XPath 1.0 grammar production 20: FilterExpr)
+    """
+    def __init__(self, filter_, predicates):
+        self._filter = filter_
         self._predicates = predicates
         return
 
     def evaluate(self, context, limit=NOLIMIT):
-        """
-        evaluate(context) -> node-set
-        Evaluate our filter into a node set, filter that through the predicates.
-        """
+        """Returns a node-set"""
+        #Evaluate our filter into a node set, filter that through the predicates.
         nodeset = self._filter.evaluate(context)
         if not isinstance(nodeset, Types.NodesetType):
-            raise TypeError("%s must be node-set, not %s" % (repr(nodeset), type(nodeset).__name__))
+            raise TypeError("%s must be a node-set, not a %s" % (repr(self._filter),
+                            Types.g_xpathPrimitiveTypes.get(type(nodeset),
+                            type(nodeset).__name__)))
 
         if nodeset:
@@ -432,5 +521,5 @@
             #with respect to the child axis, (XPath 2.4) therefore we must
             #sort into doc order before applying
-            nodeset = Util.SortDocOrder(context, nodeset)
+            nodeset.sort()
             nodeset = self._predicates.filter(nodeset, context, reverse=0)
         return nodeset
@@ -456,4 +545,8 @@
 
 class ParsedOrExpr:
+    """
+    An object representing an or expression
+    (XPath 1.0 grammar production 21: OrExpr)
+    """
     def __init__(self, left, right):
         self._left = left
@@ -467,4 +560,5 @@
 
     def evaluate(self, context, limit=NOLIMIT):
+        """Returns a boolean"""
         rt = Conversions.BooleanValue(self._left.evaluate(context))
         if not rt:
@@ -483,4 +577,8 @@
 
 class ParsedAndExpr:
+    """
+    An object representing an and expression
+    (XPath 1.0 grammar production 22: AndExpr)
+    """
     def __init__(self,left,right):
         self._left = left
@@ -494,4 +592,5 @@
 
     def evaluate(self, context, limit=NOLIMIT):
+        """Returns a boolean"""
         rt = Conversions.BooleanValue(self._left.evaluate(context))
         if rt:
@@ -509,8 +608,12 @@
 
 
-_is_number = lambda o: \
-             operator.isNumberType(o) and not isinstance(o, types.InstanceType)
+def _nodeset_compare(compare, a, b, relational=False):
+    """
+    Applies a comparison function to node-sets a and b
+    in order to evaluate equality (=, !=) and relational (<, <=, >=, >)
+    expressions in which both objects to be compared are node-sets.
 
-def _nodeset_compare(compare, a, b):
+    Returns an XPath boolean indicating the result of the comparison.
+    """
     if isinstance(a, Types.NodesetType) and isinstance(b, Types.NodesetType):
         # From XPath 1.0 Section 3.4:
@@ -520,14 +623,28 @@
         # performing the comparison on the string-values of the two nodes
         # is true.
-        if len(a) > len(b):
-            strings = map(Conversions.StringValue, a)
-            nodes = b
-        else:
-            strings = map(Conversions.StringValue, b)
-            nodes = a
-        for node in nodes:
-            current = Conversions.StringValue(node)
-            for string in strings:
-                if compare(string, current):
+        if not (a and b):
+            # One of the two node-sets is empty.  In this case, according to
+            # section 3.4 of the XPath rec, no node exists in one of the two
+            # sets to compare, so *any* comparison must be false.
+            return boolean.false
+
+        # If it is a relational comparison, the actual comparison is done on
+        # the string value of each of the nodes. This means that the values
+        # are then converted to numbers for comparison.
+        if relational:
+            # NumberValue internally coerces a node to a string before
+            # converting it to a number, so the "convert to string" clause
+            # is handled.
+            coerce = Conversions.NumberValue
+        else:
+            coerce = Conversions.StringValue
+
+        # Convert the nodesets into lists of the converted values.
+        a = map(coerce, a)
+        b = map(coerce, b)
+        # Now compare the items; if any compare True, we're done.
+        for left in a:
+            for right in b:
+                if compare(left, right):
                     return boolean.true
         return boolean.false
@@ -547,9 +664,16 @@
     # boolean and on the result of converting the node-set to a boolean using
     # the boolean function is true.
+    #
+    # (In other words, coerce each node to the same type as the other operand,
+    # then compare them. Note, however, that relational comparisons convert
+    # their operands to numbers.)
     if isinstance(a, Types.NodesetType):
         # a is nodeset
         if isinstance(b, Types.BooleanType):
             coerce = Conversions.BooleanValue
-        elif _is_number(b):
+        elif relational:
+            b = Conversions.NumberValue(b)
+            coerce = Conversions.NumberValue
+        elif isinstance(b, Types.NumberType):
             coerce = Conversions.NumberValue
         else:
@@ -563,10 +687,12 @@
         if isinstance(a, Types.BooleanType):
             coerce = Conversions.BooleanValue
-        elif _is_number(a):
+        elif relational:
+            a = Conversions.NumberValue(a)
+            coerce = Conversions.NumberValue
+        elif isinstance(a, Types.NumberType):
             coerce = Conversions.NumberValue
         else:
             a = Conversions.StringValue(a)
             coerce = Conversions.StringValue
-
         for node in b:
             if compare(a, coerce(node)):
@@ -577,4 +703,8 @@
 
 class ParsedEqualityExpr:
+    """
+    An object representing an equality expression
+    (XPath 1.0 grammar production 23: EqualityExpr)
+    """
     def __init__(self, op, left, right):
         self._op = op
@@ -584,21 +714,16 @@
 
         if op == '=':
-            self._cmp = lambda a, b: a == b
+            self._cmp = _comparisons.eq
         else:
-            self._cmp = lambda a, b: a != b
+            self._cmp = _comparisons.ne
 
     def __getstate__(self):
-        return (self._op, self._left, self._right, self._identical_operands)
+        return (self._op, self._left, self._right)
 
     def __setstate__(self, state):
-        self._op, self._left, self._right, self._identical_operands = state
-        if self._op == '=':
-            self._cmp = lambda a, b: a == b
-        else:
-            self._cmp = lambda a, b: a != b
-        return
+        self.__init__(*state)
 
     def evaluate(self, context, limit=NOLIMIT):
-
+        """Returns a boolean"""
         left = self._left.evaluate(context)
         right = self._right.evaluate(context)
@@ -618,20 +743,16 @@
             return self._op == '=' and boolean.true or boolean.false
 
-        if isinstance(left, Types.BooleanType) or \
-           isinstance(right, Types.BooleanType):
-            rt = self._cmp(Conversions.BooleanValue(left),
-                           Conversions.BooleanValue(right))
-        elif _is_number(left) or _is_number(right):
-            # note that NaN is not equal to anything, not even NaN
-            ln = Conversions.NumberValue(left)
-            rn = Conversions.NumberValue(right)
-            if number.isnan(ln) or number.isnan(rn):
-                rt = self._op == '!='
-            else:
-                rt = self._cmp(ln,rn)
+        if isinstance(left, Types.BooleanType):
+            right = Conversions.BooleanValue(right)
+        elif isinstance(right, Types.BooleanType):
+            left = Conversions.BooleanValue(left)
+        elif isinstance(left, Types.NumberType):
+            right = Conversions.NumberValue(right)
+        elif isinstance(right, Types.NumberType):
+            left = Conversions.NumberValue(left)
         else:
-            rt = self._cmp(Conversions.StringValue(left),
-                           Conversions.StringValue(right))
-        return rt and boolean.true or boolean.false
+            left = Conversions.StringValue(left)
+            right = Conversions.StringValue(right)
+        return self._cmp(left, right) and boolean.true or boolean.false
 
     def pprint(self, indent=''):
@@ -653,4 +774,8 @@
 
 class ParsedRelationalExpr:
+    """
+    An object representing a relational expression
+    (XPath 1.0 grammar production 24: RelationalExpr)
+    """
     def __init__(self, opcode, left, right):
         self._op = opcode
@@ -660,30 +785,21 @@
 
         if opcode == 0:
-            self._cmp = lambda a, b: a < b
+            self._cmp = _comparisons.lt
         elif opcode == 1:
-            self._cmp = lambda a, b: a <= b
+            self._cmp = _comparisons.le
         elif opcode == 2:
-            self._cmp = lambda a, b: a > b
+            self._cmp = _comparisons.gt
         elif opcode == 3:
-            self._cmp = lambda a, b: a >= b
+            self._cmp = _comparisons.ge
         return
 
     def __getstate__(self):
-        return (self._op, self._left, self._right, self._identical_operands)
+        return (self._op, self._left, self._right)
 
     def __setstate__(self, state):
-        self._op, self._left, self._right, self._identical_operands = state
-        if self._op == 0:
-            self._cmp = lambda a, b: a < b
-        elif self._op == 1:
-            self._cmp = lambda a, b: a <= b
-        elif self._op == 2:
-            self._cmp = lambda a, b: a > b
-        elif self._op == 3:
-            self._cmp = lambda a, b: a >= b
-        return
+        self.__init__(*state)
 
     def evaluate(self, context, limit=NOLIMIT):
-        '''returns a boolean'''
+        """Returns a boolean"""
         left = self._left.evaluate(context)
         right = self._right.evaluate(context)
@@ -691,5 +807,5 @@
         if isinstance(left, Types.NodesetType) or \
            isinstance(right, Types.NodesetType):
-            return _nodeset_compare(self._cmp, left, right)
+            return _nodeset_compare(self._cmp, left, right, relational=True)
 
         # Shortcut comparison if operands are same and not node-sets.
@@ -735,4 +851,8 @@
 
 class ParsedAdditiveExpr:
+    """
+    An object representing an additive expression
+    (XPath 1.0 grammar production 25: AdditiveExpr)
+    """
     def __init__(self, sign, left, right):
         self._sign = sign
@@ -753,5 +873,5 @@
 
     def evaluate(self, context, limit=NOLIMIT):
-        '''returns a number'''
+        '''Returns a number'''
 
         # Shortcut subtraction if operands are same and are not NaN.
@@ -799,4 +919,8 @@
 
 class ParsedMultiplicativeExpr:
+    """
+    An object representing an multiplicative expression
+    (XPath 1.0 grammar production 26: MultiplicativeExpr)
+    """
     def __init__(self, opcode, left, right):
         self._op = opcode
@@ -806,5 +930,5 @@
 
     def evaluate(self, context, limit=NOLIMIT):
-        '''returns a number'''
+        '''Returns a number'''
 
         # Shortcut division and modulo if operands are same
@@ -833,4 +957,6 @@
                 if lrt < 0:
                     res = -number.inf
+                elif lrt == 0:
+                    res = number.nan
                 else:
                     res = number.inf
@@ -868,9 +994,13 @@
 
 class ParsedUnaryExpr:
+    """
+    An object representing a unary expression
+    (XPath 1.0 grammar production 27: UnaryExpr)
+    """
     def __init__(self, exp):
         self._exp = exp
 
     def evaluate(self, context, limit=NOLIMIT):
-        '''returns a number'''
+        '''Returns a number'''
         exp = self._exp.evaluate(context)
         exp = Conversions.NumberValue(exp)
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedNodeTest.py.diff?r1=1.5.2.1&r2=1.5.2.2
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedNodeTest.py?rev=1.5.2.2&content-type=text/vnd.viewcvs-markup

Index: ParsedNodeTest.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedNodeTest.py,v
retrieving revision 1.5.2.1
retrieving revision 1.5.2.2
diff -U2 -r1.5.2.1 -r1.5.2.2
--- ParsedNodeTest.py	3 Apr 2003 14:58:13 -0000	1.5.2.1
+++ ParsedNodeTest.py	4 Dec 2006 07:06:59 -0000	1.5.2.2
@@ -1,21 +1,17 @@
 ########################################################################
-#
-# File Name:   ParsedNodeTest.py
-#
-# Docs:        http://docs.4suite.org/XPATH/ParsedNodeTest.py.html
-#
+# $Header$
 """
-A Parsed Token that represents a node test.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+A parsed token that represents a node test.
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2004 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
 from xml.dom import Node
-from Ft.Xml.XPath import NamespaceNode
-from Ft.Xml.XPath import NAMESPACE_NODE, RuntimeException
-from Ft.Xml.XPath import g_xpathRecognizedNodes 
-from Ft.Xml.XPath import NOLIMIT
+
+from Ft.Xml.XPath import RuntimeException
+from Ft.Xml.XPath.XPathTypes import g_xpathRecognizedNodes
+
 
 def ParsedNameTest(name):
@@ -29,4 +25,5 @@
     return QualifiedNameTest(name[:index], name[index+1:])
 
+
 def ParsedNodeTest(test, literal=None):
     if literal:
@@ -71,16 +68,18 @@
 
     def match(self, context, node, principalType=Node.ELEMENT_NODE):
-        return node.nodeType in g_xpathRecognizedNodes or isinstance(node, NamespaceNode.NamespaceNode)
+        return node.nodeType in g_xpathRecognizedNodes
 
     def __repr__(self):
         return 'node()'
 
+
 class CommentNodeTest(NodeTestBase):
 
     nodeType = Node.COMMENT_NODE
-    
+
     def __repr__(self):
         return 'comment()'
-    
+
+
 class TextNodeTest(NodeTestBase):
 
@@ -90,4 +89,5 @@
         return 'text()'
 
+
 class ProcessingInstructionNodeTest(NodeTestBase):
 
@@ -157,5 +157,5 @@
         self.priority = -0.25
         self._prefix = prefix
-        
+
     def getQuickKey(self, namespaces):
         # By specifing a name of None, this test will fall into the 'general'
@@ -174,5 +174,5 @@
     def __repr__(self):
         return self._prefix + ':*'
-    
+
 
 class QualifiedNameTest(NodeTestBase):
@@ -192,5 +192,5 @@
                                    self._prefix)
         return (self.nodeType, (namespace, self._localName))
-            
+
     def match(self, context, node, principalType=Node.ELEMENT_NODE):
         if node.nodeType == principalType:
@@ -212,3 +212,3 @@
     'processing-instruction' : ProcessingInstructionNodeTest,
     }
-             
+
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedPredicateList.py.diff?r1=1.5.2.1&r2=1.5.2.2
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedPredicateList.py?rev=1.5.2.2&content-type=text/vnd.viewcvs-markup

Index: ParsedPredicateList.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedPredicateList.py,v
retrieving revision 1.5.2.1
retrieving revision 1.5.2.2
diff -U2 -r1.5.2.1 -r1.5.2.2
--- ParsedPredicateList.py	3 Apr 2003 14:58:13 -0000	1.5.2.1
+++ ParsedPredicateList.py	4 Dec 2006 07:06:59 -0000	1.5.2.2
@@ -2,7 +2,7 @@
 # $Header$
 """
-A Parsed Token that represents a predicate list.
+A parsed token that represents a predicate list.
 
-Copyright 2003 Fourthought, Inc. (USA).
+Copyright 2005 Fourthought, Inc. (USA).
 Detailed license and copyright information: http://4suite.org/COPYRIGHT
 Project home, documentation, distributions: http://4suite.org/
@@ -11,13 +11,13 @@
 from Ft.Lib import number
 from Ft.Xml.XPath import Conversions
-import types
-NumberTypes = [types.IntType, types.LongType, types.FloatType]
+from Ft.Xml.XPath.XPathTypes import NumberTypes, g_xpathPrimitiveTypes
 
+__all__ = ['ParsedPredicateList']
 
 class ParsedPredicateList:
     def __init__(self, preds):
-        if type(preds) == type(()):
+        if isinstance(preds, tuple):
             preds = list(preds)
-        elif not type(preds) == type([]):
+        elif not isinstance(preds, list):
             raise TypeError("Invalid Predicates: %s"%str(preds))
 
@@ -27,5 +27,5 @@
     def append(self, pred):
         self._predicates.append(pred)
-        self._length = self._length + 1
+        self._length += 1
 
     def filter(self, nodeList, context, reverse):
@@ -49,5 +49,5 @@
                     elif Conversions.BooleanValue(res):
                         nodeList.append(node)
-                    ctr = ctr + 1
+                    ctr += 1
             context.set(state)
         return nodeList
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedRelativeLocationPath.py.diff?r1=1.3.2.2&r2=1.3.2.3
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedRelativeLocationPath.py?rev=1.3.2.3&content-type=text/vnd.viewcvs-markup

Index: ParsedRelativeLocationPath.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedRelativeLocationPath.py,v
retrieving revision 1.3.2.2
retrieving revision 1.3.2.3
diff -U2 -r1.3.2.2 -r1.3.2.3
--- ParsedRelativeLocationPath.py	3 Apr 2003 14:58:13 -0000	1.3.2.2
+++ ParsedRelativeLocationPath.py	4 Dec 2006 07:06:59 -0000	1.3.2.3
@@ -1,14 +1,10 @@
-########################################################################
-#
-# File Name:   ParsedRelativeLocationPath.py
-#
-# Docs:        http://docs.4suite.org/XPATH/ParsedRelativeLocationPath.py.html
-#
+########################################################################  
+# $Header$
 """
-A Parsed Token that represents a relative location path in the parsed result tree.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
-
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+A parsed token that represents a relative location path in the parsed result tree.
+    
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
@@ -28,5 +24,5 @@
         result = []
         size = len(nodeset)
-        for pos in range(size):
+        for pos in xrange(size):
             context.node, context.position, context.size = \
                           nodeset[pos], pos + 1, size
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedStep.py.diff?r1=1.4.2.2&r2=1.4.2.3
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/ParsedStep.py?rev=1.4.2.3&content-type=text/vnd.viewcvs-markup

Index: ParsedStep.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/ParsedStep.py,v
retrieving revision 1.4.2.2
retrieving revision 1.4.2.3
diff -U2 -r1.4.2.2 -r1.4.2.3
--- ParsedStep.py	3 Apr 2003 14:58:13 -0000	1.4.2.2
+++ ParsedStep.py	4 Dec 2006 07:06:59 -0000	1.4.2.3
@@ -1,19 +1,16 @@
 ########################################################################
-#
-# File Name:   ParsedStep.py
-#
-# Docs:        http://docs.4suite.org/XPATH/ParsedStep.py.html
-#
+# $Header$
 """
-A Parsed token that represents a step on the result tree.
-WWW: http://4suite.org/XPATH        e-mail: support at 4suite.org
+A parsed token that represents a step.
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2004 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
 from xml.dom import Node
+
 from Ft.Lib import number
-from Ft.Xml.XPath import Types, Context, NOLIMIT
+from Ft.Xml.XPath import XPathTypes as Types, Context, NOLIMIT
 import types
 NumberTypes = [types.IntType, types.LongType, types.FloatType]
@@ -102,5 +99,8 @@
         nodeset = self._function.evaluate(context)
         if not isinstance(nodeset, Types.NodesetType):
-            raise TypeError("must be nodeset, not %s" % type(nodeset).__name__)
+            raise TypeError("%s must be a node-set, not a %s" % (repr(self._function),
+                            Types.g_xpathPrimitiveTypes.get(type(nodeset),
+                            type(nodeset).__name__)))
+
         if self._predicates and len(nodeset):
             reverse = 0
--- Types.py DELETED ---
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/Util.py.diff?r1=1.14&r2=1.14.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/Util.py?rev=1.14.2.1&content-type=text/vnd.viewcvs-markup

Index: Util.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/Util.py,v
retrieving revision 1.14
retrieving revision 1.14.2.1
diff -U2 -r1.14 -r1.14.2.1
--- Util.py	31 Jan 2003 07:25:35 -0000	1.14
+++ Util.py	4 Dec 2006 07:06:59 -0000	1.14.2.1
@@ -1,113 +1,42 @@
 ########################################################################
-#
-# File Name:            Util.py
-#
-# Documentation:        http://docs.4suite.org/4XSLT/Util.py.html
-#
+# $Header$
 """
-General Utilities for XPath apps.
-WWW: http://4suite.org/4XSLT        e-mail: support at 4suite.org
+General utilities for XPath applications
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-import os, glob, string
-from Ft.Xml import SplitQName
-from Ft.Xml import Domlette, XML_NAMESPACE, XMLNS_NAMESPACE, EMPTY_NAMESPACE
+import os
 from xml.dom import Node
-from Ft.Xml.XPath import g_xpathRecognizedNodes
-from Ft.Xml.XPath.NamespaceNode import NamespaceNode
-from Ft.Xml.XPath import RuntimeException
-
-g_documentOrderIndex = {}
-g_documentIdIndex = {}
-
-def GetElementById(document, name):
-    if not g_documentIdIndex.has_key(id(document)):
-        # First time through for this document, build ID index
-        g_documentIdIndex[id(document)] = mapping = {}
-        ElementsById(document.documentElement, mapping)
-
-    elements = g_documentIdIndex[id(document)].get(name, [None])
-    if len(elements) > 1:
-        raise ValueError("ID not unique")
-    return elements[0]
-
-
-def ElementsById(element, mapping):
-    idattr = element.getAttributeNodeNS(EMPTY_NAMESPACE, 'ID') or \
-             element.getAttributeNodeNS(EMPTY_NAMESPACE, 'id')
-    if idattr:
-        mapping.setdefault(idattr.value, []).append(idattr.ownerElement)
-
-    for element in filter(lambda node: node.nodeType == Node.ELEMENT_NODE,
-                          element.childNodes):
-        ElementsById(element, mapping)
-    return
-
-
-def IndexDocument(doc):
-    global g_documentOrderIndex
-    if g_documentOrderIndex.has_key(id(doc)):
-        return
-    mapping = {}
-    __IndexNode(doc, 0, mapping)
-    g_documentOrderIndex[id(doc)] = mapping
-
-
-def FreeDocumentIndex(doc):
-    global g_documentOrderIndex
-    try:
-        del g_documentOrderIndex[id(doc)]
-    except KeyError:
-        pass
-    try:
-        del g_documentIdIndex[id(doc)]
-    except KeyError:
-        pass
-    return
-
-def SortDocOrder(context, nodeset):
-    if len(nodeset) <= 1:
-        return nodeset
-
-    # Determine if the nodeset contains mixed documents
-    documents = {}
-    for node in nodeset:
-        documents[node.rootNode] = 1
-
-    if len(documents) > 1:
-        # Mixed documents, split the nodesets based on document
-        nodesets = []
-        documents = documents.keys()
-        documents.sort(context.compareDocuments)
-        for document in documents:
-            nodesets.append(filter(lambda node, doc=document:
-                                   node.rootNode == doc,
-                                   nodeset))
-
-        sorted = []
-        for nodeset in nodesets:
-            decorated = [ (node.docIndex, node) for node in nodeset ]
-            decorated.sort()
-            sorted.extend([ item[1] for item in decorated ])
-
-    else:
-        decorated = [ (node.docIndex, node) for node in nodeset ]
-        decorated.sort()
-        sorted = [ item[1] for item in decorated ]
 
-    return sorted
+from Ft.Xml import EMPTY_NAMESPACE
+from Ft.Xml.Domlette import GetAllNs
+from Ft.Xml.Lib.XmlString import SplitQName
+
+# NOTE: XPathParser and Context are added to this module by __init__.py
+
+__all__ = [# XPath expression parser:
+           #'XPathParser', #is this necessary to expose?
+           # XPath expression processing:
+           'Compile', 'Evaluate', 'SimpleEvaluate',
+           # DOM preparation for XPath processing:
+           'NormalizeNode',
+           # misc XPath related utilities:
+           'ExpandQName',
+           ]
 
 
 def ExpandQName(qname, refNode=None, namespaces=None):
-    '''
+    """
     Expand the given QName in the context of the given node,
-    or in the given namespace dictionary
-    '''
+    or in the given namespace dictionary.
+
+    Returns a 2-tuple consisting of the namespace URI and local name.
+    """
     nss = {}
     if refNode:
-        nss = Domlette.GetAllNs(refNode)
+        nss = GetAllNs(refNode)
     elif namespaces:
         nss = namespaces
@@ -118,4 +47,5 @@
             split_name = (nss[prefix], local)
         except KeyError:
+            from Ft.Xml.XPath import RuntimeException
             raise RuntimeException(RuntimeException.UNDEFINED_PREFIX,
                                    prefix)
@@ -125,66 +55,10 @@
 
 
-def __IndexNode(node, curIndex, mapping):
-    if node.nodeType in g_xpathRecognizedNodes:
-        #Add this node
-        mapping[id(node)] = curIndex
-        curIndex = curIndex + 1
-
-        if node.nodeType == Node.ELEMENT_NODE:
-            # Leave a space for namespace nodes
-            curIndex += 1
-
-            # It is OK for attributes to be unordered
-            for attr in node.attributes.values():
-                mapping[id(attr)] = curIndex
-                curIndex += 1
-
-        for childNode in node.childNodes:
-            curIndex = __IndexNode(childNode, curIndex, mapping)
-
-    return curIndex
-
-
-def GetIndex(node):
-    nid = id(node)
-    docId = id(node.rootNode)
-    try:
-        ix = g_documentOrderIndex[docId][nid]
-    except KeyError:
-        #Must be namespace node in there
-        if isinstance(node, NamespaceNode):
-            nid = id(node.parentNode)
-            ix = g_documentOrderIndex[docId][nid] + 1
-    return ix
-
-
-def __recurseSort(test, toSort):
-    """Check whether any of the nodes in toSort are in the list test, and if so, sort them into the result list"""
-    result = []
-    for node in test:
-        toSort = filter(lambda x, n=node: x != n, toSort)
-        if node in toSort:
-            result.append(node)
-        #See if node has attributes
-        if node.nodeType == Node.ELEMENT_NODE:
-            attrList = node.attributes.values()
-            #FIXME: Optimize by unrolling this level of recursion
-            result = result + __recurseSort(attrList, toSort)
-            if not toSort:
-                #Exit early
-                break
-        #See if any of t's children are in toSort
-        result = result + __recurseSort(node.childNodes, toSort)
-        if not toSort:
-            #Exit early
-            break
-    return result
-
-
 def NormalizeNode(node):
-    """NormalizeNode is used to prepare a DOM for XPath evaluation.
+    """
+    NormalizeNode is used to prepare a DOM for XPath evaluation.
 
     1.  Convert CDATA Sections to Text Nodes.
-    2.  Normalize all text nodes
+    2.  Normalize all text nodes (adjacent nodes are merged into the first one).
     """
     node = node.firstChild
@@ -228,2 +102,114 @@
     return
 
+
+# -- Core XPath API ---------------------------------------------------------
+
+
+def SimpleEvaluate(expr, node, explicitNss=None):
+    """
+    Designed to be the most simple/brain-dead interface to using XPath
+    Usually invoked through Node objects using:
+      node.xpath(expr[, explicitNss])
+
+    expr - XPath expression in string or compiled form
+    node - the node to be used as core of the context for evaluating the XPath
+    explicitNss - (optional) any additional or overriding namespace mappings
+                  in the form of a dictionary of prefix: namespace
+                  the base namespace mappings are taken from in-scope
+                  declarations on the given node.  This explicit dictionary
+                  is superimposed on the base mappings
+    """
+    if 'EXTMODULES' in os.environ:
+        ext_modules = os.environ["EXTMODULES"].split(':')
+    else:
+        ext_modules = []
+    explicitNss = explicitNss or {}
+
+    nss = GetAllNs(node)
+    nss.update(explicitNss)
+    context = Context.Context(node, 0, 0, processorNss=nss,
+                              extModuleList=ext_modules)
+
+    if hasattr(expr, "evaluate"):
+        retval = expr.evaluate(context)
+    else:
+        retval = XPathParser.new().parse(expr).evaluate(context)
+    return retval
+
+
+def Evaluate(expr, contextNode=None, context=None):
+    """
+    Evaluates the given XPath expression.
+
+    Two arguments are required: the expression (as a string or compiled
+    expression object), and a context. The context can be given as a
+    Domlette node via the 'contextNode' named argument, or can be given as
+    an Ft.Xml.XPath.Context.Context object via the 'context' named
+    argument.
+
+    If namespace bindings or variable bindings are needed, use a
+    Context object. If extension functions are needed, either use a
+    Context object, or set the EXTMODULES environment variable to be a
+    ':'-separated list of names of Python modules that implement
+    extension functions.
+
+    The return value will be one of the following:
+    node-set: list of Domlette node objects (xml.dom.Node based);
+    string: Unicode string type;
+    number: float type;
+    boolean: Ft.Lib.boolean C extension object;
+    or a non-XPath object (i.e. as returned by an extension function).
+    """
+    if 'EXTMODULES' in os.environ:
+        ext_modules = os.environ["EXTMODULES"].split(':')
+    else:
+        ext_modules = []
+
+    if contextNode and context:
+        con = context.clone()
+        con.node = contextNode
+    elif context:
+        con = context
+    elif contextNode:
+        #contextNode should be a node, not a context obj,
+        #but this is a common error.  Be forgiving?
+        if isinstance(contextNode, Context.Context):
+            con = contextNode
+        else:
+            con = Context.Context(contextNode, 0, 0, extModuleList=ext_modules)
+    else:
+        # import here to avoid circularity
+        from Ft.Xml.XPath import RuntimeException
+        raise RuntimeException(RuntimeException.NO_CONTEXT)
+
+    if hasattr(expr, "evaluate"):
+        retval = expr.evaluate(con)
+    else:
+        retval = XPathParser.new().parse(expr).evaluate(con)
+    return retval
+
+
+def Compile(expr):
+    """
+    Given an XPath expression as a string, returns an object that allows
+    an evaluation engine to operate on the expression efficiently.
+    This "compiled" expression object can be passed to the Evaluate
+    function instead of a string, in order to shorten the amount of time
+    needed to evaluate the expression.
+    """
+    if not isinstance(expr, (str, unicode)):
+        raise TypeError("Expected string, found %s" % type(expr))
+    try:
+        return XPathParser.new().parse(expr)
+    except SyntaxError, error:
+        # import here to avoid circularity
+        from Ft.Xml.XPath import CompiletimeException
+        raise CompiletimeException(CompiletimeException.SYNTAX, 0, 0, str(error))
+    except:
+        import traceback, cStringIO
+        stream = cStringIO.StringIO()
+        traceback.print_exc(None, stream)
+        # import here to avoid circularity
+        from Ft.Xml.XPath import CompiletimeException
+        raise CompiletimeException(CompiletimeException.INTERNAL, stream.getvalue())
+
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPath.bgen.diff?r1=1.2&r2=1.2.10.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPath.bgen?rev=1.2.10.1&content-type=text/vnd.viewcvs-markup

Index: XPath.bgen
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/XPath.bgen,v
retrieving revision 1.2
retrieving revision 1.2.10.1
diff -U2 -r1.2 -r1.2.10.1
--- XPath.bgen	3 Jun 2002 01:01:02 -0000	1.2
+++ XPath.bgen	4 Dec 2006 07:06:59 -0000	1.2.10.1
@@ -1,4 +1,4 @@
 <?xml version='1.0'?>
-<bisongen version='1.0' name='XPathParser' project='Ft.XPath'>
+<bisongen version='1.0' name='XPathParser' project='Ft.Xml.XPath'>
 
   <!-- Python modules to import -->
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathBase.bgen.frag.diff?r1=1.1&r2=1.1.22.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathBase.bgen.frag?rev=1.1.22.1&content-type=text/vnd.viewcvs-markup

Index: XPathBase.bgen.frag
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/XPathBase.bgen.frag,v
retrieving revision 1.1
retrieving revision 1.1.22.1
diff -U2 -r1.1 -r1.1.22.1
--- XPathBase.bgen.frag	15 Sep 2001 18:20:48 -0000	1.1
+++ XPathBase.bgen.frag	4 Dec 2006 07:06:59 -0000	1.1.22.1
@@ -16,8 +16,8 @@
     <symbol>'/'</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", Py_None);
+      $$ = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", Py_None);
     </code>
     <code language="python">
-      $$ = ParsedAbsoluteLocationPath.ParsedAbsoluteLocationPath(None)
+      $$ = ParsedAbsoluteLocationPath(None)
     </code>
   </rule>
@@ -26,8 +26,8 @@
     <symbol>relativeLocationPath</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", $2);
+      $$ = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", $2);
     </code>
     <code language="python">
-      $$ = ParsedAbsoluteLocationPath.ParsedAbsoluteLocationPath($2)
+      $$ = ParsedAbsoluteLocationPath($2)
     </code>
   </rule>
@@ -47,8 +47,8 @@
     <symbol>step</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedRelativeLocationPath, "ParsedRelativeLocationPath", "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedRelativeLocationPath, "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedRelativeLocationPath.ParsedRelativeLocationPath($1, $3)
+      $$ = ParsedRelativeLocationPath($1, $3)
     </code>
   </rule>
@@ -64,8 +64,8 @@
     <symbol>nodeTest</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedStep, "ParsedStep", "OO", $1, $2);
+      $$ = PyObject_CallFunction(ParsedStep, "OO", $1, $2);
     </code>
     <code language="python">
-      $$ = ParsedStep.ParsedStep($1, $2)
+      $$ = ParsedStep($1, $2)
     </code>
   </rule>
@@ -75,8 +75,8 @@
     <symbol>predicateList</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedStep, "ParsedStep", "OOO", $1, $2, $3);
+      $$ = PyObject_CallFunction(ParsedStep, "OOO", $1, $2, $3);
     </code>
     <code language="python">
-      $$ = ParsedStep.ParsedStep($1, $2, $3)
+      $$ = ParsedStep($1, $2, $3)
     </code>
   </rule>
@@ -95,9 +95,9 @@
       PyList_SET_ITEM(pred_list, 0, $1);
       Py_INCREF($1);
-      $$ = PyObject_CallMethod(ParsedPredicateList, "ParsedPredicateList", "O", pred_list);
+      $$ = PyObject_CallFunction(ParsedPredicateList, "O", pred_list);
       Py_DECREF(pred_list);
     </code>
     <code language="python">
-      $$ = ParsedPredicateList.ParsedPredicateList([$1])
+      $$ = ParsedPredicateList([$1])
     </code>
   </rule>
@@ -123,8 +123,8 @@
     <symbol>DOUBLE_COLON</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "O", $1);
+      $$ = PyObject_CallFunction(ParsedAxisSpecifier, "O", $1);
     </code>
     <code language="python">
-      $$ = ParsedAxisSpecifier.ParsedAxisSpecifier($1)
+      $$ = ParsedAxisSpecifier($1)
     </code>
   </rule>
@@ -150,8 +150,8 @@
     <symbol>WILDCARD_NAME</symbol>
     <code language="C">
-      $$ = PyObject_CallMethod(ParsedNodeTest, "ParsedNameTest", "O", $1);
+      $$ = PyObject_CallFunction(ParsedNameTest, "O", $1);
     </code>
     <code language="python">
-      $$ = ParsedNodeTest.ParsedNameTest($1)
+      $$ = ParsedNameTest($1)
     </code>
   </rule>
@@ -161,8 +161,8 @@
     <symbol>')'</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "O", $1);
+      $$ = PyObject_CallFunction(ParsedNodeTest, "O", $1);
     </code>
     <code language="python">
-      $$ = ParsedNodeTest.ParsedNodeTest($1)
+      $$ = ParsedNodeTest($1)
     </code>
   </rule>
@@ -173,8 +173,8 @@
     <symbol>')'</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedNodeTest, "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedNodeTest.ParsedNodeTest($1, $3)
+      $$ = ParsedNodeTest($1, $3)
     </code>
   </rule>
@@ -210,10 +210,9 @@
     <symbol>relativeLocationPath</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAbbreviatedAbsoluteLocationPath,
-                               "ParsedAbbreviatedAbsoluteLocationPath",
-                               "O", $2);
+      $$ = PyObject_CallFunction(ParsedAbbreviatedAbsoluteLocationPath,
+                                 "O", $2);
     </code>
     <code language="python">
-      $$ = ParsedAbbreviatedAbsoluteLocationPath.ParsedAbbreviatedAbsoluteLocationPath($2)
+      $$ = ParsedAbbreviatedAbsoluteLocationPath($2)
     </code>
   </rule>
@@ -227,10 +226,9 @@
     <symbol>step</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAbbreviatedRelativeLocationPath,
-                               "ParsedAbbreviatedRelativeLocationPath",
-                               "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedAbbreviatedRelativeLocationPath,
+                                 "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedAbbreviatedRelativeLocationPath.ParsedAbbreviatedRelativeLocationPath($1, $3)
+      $$ = ParsedAbbreviatedRelativeLocationPath($1, $3)
     </code>
   </rule>
@@ -242,8 +240,8 @@
     <symbol>'.'</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 0);
+      $$ = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 0);
     </code>
     <code language="python">
-      $$ = ParsedStep.ParsedAbbreviatedStep(0)
+      $$ = ParsedAbbreviatedStep(0)
     </code>
   </rule>
@@ -251,8 +249,8 @@
     <symbol>DOUBLE_DOT</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 1);
+      $$ = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 1);
     </code>
     <code language="python">
-      $$ = ParsedStep.ParsedAbbreviatedStep(1)
+      $$ = ParsedAbbreviatedStep(1)
     </code>
   </rule>
@@ -264,16 +262,16 @@
     <symbol>'@'</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "attribute");
+      $$ = PyObject_CallFunction(ParsedAxisSpecifier, "s", "attribute");
     </code>
     <code language="python">
-      $$ = ParsedAxisSpecifier.ParsedAxisSpecifier("attribute")
+      $$ = ParsedAxisSpecifier("attribute")
     </code>
   </rule>
   <rule>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "child");
+      $$ = PyObject_CallFunction(ParsedAxisSpecifier, "s", "child");
     </code>
     <code language="python">
-      $$ = ParsedAxisSpecifier.ParsedAxisSpecifier("child")
+      $$ = ParsedAxisSpecifier("child")
     </code>
   </rule>
@@ -293,8 +291,8 @@
     <symbol>VARIABLE_REFERENCE</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedVariableReferenceExpr", "O", $1);
+      $$ = PyObject_CallFunction(ParsedVariableReferenceExpr, "O", $1);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedVariableReferenceExpr($1)
+      $$ = ParsedVariableReferenceExpr($1)
     </code>
   </rule>
@@ -314,8 +312,8 @@
     <symbol>LITERAL</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedLiteralExpr", "O", $1);
+      $$ = PyObject_CallFunction(ParsedLiteralExpr, "O", $1);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedLiteralExpr($1)
+      $$ = ParsedLiteralExpr($1)
     </code>
   </rule>
@@ -323,8 +321,8 @@
     <symbol>NLITERAL</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedNLiteralExpr", "O", $1);
+      $$ = PyObject_CallFunction(ParsedNLiteralExpr, "O", $1);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedNLiteralExpr($1)
+      $$ = ParsedNLiteralExpr($1)
     </code>
   </rule>
@@ -343,9 +341,9 @@
     <code language="c">
       PyObject *arg_list = PyList_New(0);
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedFunctionCallExpr", "OO", $1, arg_list);
+      $$ = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", $1, arg_list);
       Py_DECREF(arg_list);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedFunctionCallExpr($1, [])
+      $$ = ParsedFunctionCallExpr($1, [])
     </code>
   </rule>
@@ -356,8 +354,8 @@
     <symbol>')'</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr ,"ParsedFunctionCallExpr", "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedFunctionCallExpr($1, $3)
+      $$ = ParsedFunctionCallExpr($1, $3)
     </code>
   </rule>
@@ -412,8 +410,8 @@
     <symbol>pathExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedUnionExpr", "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedUnionExpr, "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedUnionExpr($1, $3)
+      $$ = ParsedUnionExpr($1, $3)
     </code>
   </rule>
@@ -433,8 +431,8 @@
     <symbol>relativeLocationPath</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 0, $1, $3);
+      $$ = PyObject_CallFunction(ParsedPathExpr, "iOO", 0, $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedPathExpr($2, $1, $3)
+      $$ = ParsedPathExpr($2, $1, $3)
     </code>
   </rule>
@@ -444,8 +442,8 @@
     <symbol>relativeLocationPath</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 1, $1, $3);
+      $$ = PyObject_CallFunction(ParsedPathExpr, "iOO", 1, $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedPathExpr($2, $1, $3)
+      $$ = ParsedPathExpr($2, $1, $3)
     </code>
   </rule>
@@ -462,8 +460,8 @@
     <symbol>predicateList</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedFilterExpr", "OO", $1, $2);
+      $$ = PyObject_CallFunction(ParsedFilterExpr, "OO", $1, $2);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedFilterExpr($1, $2)
+      $$ = ParsedFilterExpr($1, $2)
     </code>
   </rule>
@@ -480,8 +478,8 @@
     <symbol>andExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedOrExpr", "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedOrExpr, "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedOrExpr($1, $3)
+      $$ = ParsedOrExpr($1, $3)
     </code>
   </rule>
@@ -498,8 +496,8 @@
     <symbol>equalityExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedAndExpr", "OO", $1, $3);
+      $$ = PyObject_CallFunction(ParsedAndExpr, "OO", $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedAndExpr($1, $3)
+      $$ = ParsedAndExpr($1, $3)
     </code>
   </rule>
@@ -516,8 +514,8 @@
     <symbol>relationalExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedEqualityExpr", "OOO", $2, $1, $3);
+      $$ = PyObject_CallFunction(ParsedEqualityExpr, "OOO", $2, $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedEqualityExpr($2, $1, $3)
+      $$ = ParsedEqualityExpr($2, $1, $3)
     </code>
   </rule>
@@ -538,15 +536,15 @@
         if (op[1] == '=') {
           /* less than or equal to */
-          $$ = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 1, $1, $3);
+          $$ = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 1, $1, $3);
         } else {
           /* less than */
-          $$ = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 0, $1, $3);
+          $$ = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 0, $1, $3);
         }
       } else if (op[1] == '=') {
         /* greater than or equal to */
-        $$ = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 3, $1, $3);
+        $$ = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 3, $1, $3);
       } else {
         /* greater than */
-        $$ = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 2, $1, $3);
+        $$ = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 2, $1, $3);
       }    
     </code>
@@ -557,5 +555,5 @@
              '&gt;=' : 3,
              }
-      $$ = ParsedExpr.ParsedRelationalExpr(ops[$2], $1, $3)
+      $$ = ParsedRelationalExpr(ops[$2], $1, $3)
     </code>
   </rule>
@@ -572,8 +570,8 @@
     <symbol>multiplicativeExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", 1, $1, $3);
+      $$ = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", 1, $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedAdditiveExpr(1, $1, $3)
+      $$ = ParsedAdditiveExpr(1, $1, $3)
     </code>
   </rule>
@@ -583,8 +581,8 @@
     <symbol>multiplicativeExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", -1, $1, $3);
+      $$ = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", -1, $1, $3);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedAdditiveExpr(-1, $1, $3)
+      $$ = ParsedAdditiveExpr(-1, $1, $3)
     </code>
   </rule>
@@ -604,13 +602,13 @@
       switch (*op) {
         case '*': {
-          $$ = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 0, $1, $3);
+          $$ = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 0, $1, $3);
           break;
         }
         case 'd': {
-          $$ = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 1, $1, $3);
+          $$ = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 1, $1, $3);
           break;
         }
         case 'm': {
-          $$ = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 2, $1, $3);
+          $$ = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 2, $1, $3);
           break;
         }
@@ -622,5 +620,5 @@
              'mod' : 2,
              }
-      $$ = ParsedExpr.ParsedMultiplicativeExpr(ops[$2], $1, $3)
+      $$ = ParsedMultiplicativeExpr(ops[$2], $1, $3)
     </code>
   </rule>
@@ -636,8 +634,8 @@
     <symbol>unionExpr</symbol>
     <code language="c">
-      $$ = PyObject_CallMethod(ParsedExpr, "ParsedUnaryExpr", "O", $2);
+      $$ = PyObject_CallFunction(ParsedUnaryExpr, "O", $2);
     </code>
     <code language="python">
-      $$ = ParsedExpr.ParsedUnaryExpr($2)
+      $$ = ParsedUnaryExpr($2)
     </code>
   </rule>
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathLexerDefines.bgen.frag.diff?r1=1.2&r2=1.2.18.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathLexerDefines.bgen.frag?rev=1.2.18.1&content-type=text/vnd.viewcvs-markup

Index: XPathLexerDefines.bgen.frag
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/XPathLexerDefines.bgen.frag,v
retrieving revision 1.2
retrieving revision 1.2.18.1
diff -U2 -r1.2 -r1.2.18.1
--- XPathLexerDefines.bgen.frag	14 Dec 2001 21:34:46 -0000	1.2
+++ XPathLexerDefines.bgen.frag	4 Dec 2006 07:06:59 -0000	1.2.18.1
@@ -2,31 +2,29 @@
 <fragment>
   <!-- from http://www.w3.org/TR/REC-xml#NT-S -->
-  <define name='S'>[\t\n\r\s]</define>
+  <define name='S'>[\t\n\r\x20]</define>
 
   <!-- from http://www.w3.org/TR/REC-xml#NT-BaseChar -->
-  <define name='BaseChar'>\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3</define>
+  <define name='BaseChar'>[\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3]</define>
 
   <!-- from http://www.w3.org/TR/REC-xml#NT-Ideographic -->
-  <define name='Ideographic'>\u4E00-\u9FA5\u3007\u3021-\u3029</define>
+  <define name='Ideographic'>[\u4E00-\u9FA5\u3007\u3021-\u3029]</define>
   
   <!-- from http://www.w3.org/TR/REC-xml#NT-CombiningChar -->
-  <define name='CombiningChar'>\u0300-\u0345\u0360-\u0361\u0483-\u0486\u0591-\u05A1\u05A3-\u05B9\u05BB-\u05BD\u05BF\u05C1-\u05C2\u05C4\u064B-\u0652\u0670\u06D6-\u06DC\u06DD-\u06DF\u06E0-\u06E4\u06E7-\u06E8\u06EA-\u06ED\u0901-\u0903\u093C\u093E-\u094C\u094D\u0951-\u0954\u0962-\u0963\u0981-\u0983\u09BC\u09BE\u09BF\u09C0-\u09C4\u09C7-\u09C8\u09CB-\u09CD\u09D7\u09E2-\u09E3\u0A02\u0A3C\u0A3E\u0A3F\u0A40-\u0A42\u0A47-\u0A48\u0A4B-\u0A4D\u0A70-\u0A71\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0B01-\u0B03\u0B3C\u0B3E-\u0B43\u0B47-\u0B48\u0B4B-\u0B4D\u0B56-\u0B57\u0B82-\u0B83\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55-\u0C56\u0C82-\u0C83\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5-\u0CD6\u0D02-\u0D03\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EC8-\u0ECD\u0F18-\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86-\u0F8B\u0F90-\u0F95\u0F97\u0F99-\u0FAD\u0FB1-\u0FB7\u0FB9\u20D0-\u20DC\u20E1\u302A-\u302F\u3099\u309A</define>
+  <define name='CombiningChar'>[\u0300-\u0345\u0360-\u0361\u0483-\u0486\u0591-\u05A1\u05A3-\u05B9\u05BB-\u05BD\u05BF\u05C1-\u05C2\u05C4\u064B-\u0652\u0670\u06D6-\u06DC\u06DD-\u06DF\u06E0-\u06E4\u06E7-\u06E8\u06EA-\u06ED\u0901-\u0903\u093C\u093E-\u094C\u094D\u0951-\u0954\u0962-\u0963\u0981-\u0983\u09BC\u09BE\u09BF\u09C0-\u09C4\u09C7-\u09C8\u09CB-\u09CD\u09D7\u09E2-\u09E3\u0A02\u0A3C\u0A3E\u0A3F\u0A40-\u0A42\u0A47-\u0A48\u0A4B-\u0A4D\u0A70-\u0A71\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0B01-\u0B03\u0B3C\u0B3E-\u0B43\u0B47-\u0B48\u0B4B-\u0B4D\u0B56-\u0B57\u0B82-\u0B83\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55-\u0C56\u0C82-\u0C83\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5-\u0CD6\u0D02-\u0D03\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EC8-\u0ECD\u0F18-\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86-\u0F8B\u0F90-\u0F95\u0F97\u0F99-\u0FAD\u0FB1-\u0FB7\u0FB9\u20D0-\u20DC\u20E1\u302A-\u302F\u3099\u309A]</define>
 
   <!-- from http://www.w3.org/TR/REC-xml#NT-Digit -->
-  <define name='Digit'>\u0030-\u0039\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE7-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29</define>
+  <define name='Digit'>[\u0030-\u0039\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE7-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29]</define>
 
   <!-- from http://www.w3.org/TR/REC-xml#NT-Extender -->
-  <define name='Extender'>\u00B7\u02D0\u02D1\u0387\u0640\u0E46\u0EC6\u3005\u3031-\u3035\u309D-\u309E\u30FC-\u30FE</define>
+  <define name='Extender'>[\u00B7\u02D0\u02D1\u0387\u0640\u0E46\u0EC6\u3005\u3031-\u3035\u309D-\u309E\u30FC-\u30FE]</define>
 
   <!-- from http://www.w3.org/TR/REC-xml#NT-Letter -->
-  <define name='Letter'>{BaseChar}{Ideographic}</define>
+  <define name='Letter'>{BaseChar}|{Ideographic}</define>
 
   <!-- from http://www.w3.org/TR/REC-xml-names/#NT-NCNameChar -->
-  <define name='NCNameChar'>{Letter}{Digit}\.\-_{CombiningChar}{Extender}</define>
+  <define name='NCNameChar'>{Letter}|{Digit}|\.|-|_|{CombiningChar}|{Extender}</define>
 
   <!-- from http://www.w3.org/TR/REC-xml-names/#NT-NCName -->
-  <!-- FIXME - This is currently too slow to allow, revisit after finishing DFA lexer -->
-  <!--define name='NCName'>[{Letter}_][{NCNameChar}]*</define-->
-  <define name='NCName'>[a-zA-Z_][a-zA-Z0-9_.-]*</define>
+  <define name='NCName'>({Letter}|_){NCNameChar}*</define>
 
   <!-- from http://www.w3.org/TR/REC-xml-names#NT-QName -->
@@ -34,8 +32,8 @@
 
   <!-- from http://www.w3.org/TR/xpath#NT-Digits -->
-  <define name='Digits'>[0-9]+</define>
+  <define name='Digits'>{Digit}+</define>
 
   <!-- from http://www.w3.org/TR/xpath#NT-Literal -->
-  <define name='Literal'>('[^']*')|("[^"]*")</define>
+  <define name='Literal'>('[^']*')|(\"[^"]*\")</define>
 
   <!-- from http://www.w3.org/TR/xpath#NT-NodeType -->
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathLexerPatterns.bgen.frag.diff?r1=1.3&r2=1.3.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathLexerPatterns.bgen.frag?rev=1.3.2.1&content-type=text/vnd.viewcvs-markup

Index: XPathLexerPatterns.bgen.frag
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/XPathLexerPatterns.bgen.frag,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -U2 -r1.3 -r1.3.2.1
--- XPathLexerPatterns.bgen.frag	17 Jan 2003 09:36:48 -0000	1.3
+++ XPathLexerPatterns.bgen.frag	4 Dec 2006 07:06:59 -0000	1.3.2.1
@@ -22,5 +22,5 @@
 
       <!-- ignore whitespace, defined here for speed -->
-      <pattern expression='{S}'/>
+      <pattern expression='{S}+'/>
 
       <pattern expression='.'>
@@ -39,5 +39,5 @@
     </pattern>
 
-    <pattern expression='//'>
+    <pattern expression='"//"'>
       <begin>INITIAL</begin>
       <token>DOUBLE_SLASH</token>
@@ -55,10 +55,10 @@
 
     <!-- node types -->
-    <pattern expression='{NodeType}(?={S}*\()'>
+    <pattern expression='{NodeType}/{S}*\('>
       <token>NODE_TYPE</token>
     </pattern>
 
     <!-- axis specifiers -->
-    <pattern expression='{NCName}(?={S}*::)'>
+    <pattern expression='{NCName}/{S}*::'>
       <token>AXIS_NAME</token>
     </pattern>
@@ -80,5 +80,5 @@
     </pattern>
 
-    <pattern expression='{QName}(?={S}*\()'>
+    <pattern expression='{QName}/{S}*\('>
       <token>FUNCTION_NAME</token>
     </pattern>
@@ -89,5 +89,5 @@
     </pattern>
 
-    <pattern expression='\.\.'>
+    <pattern expression='".."'>
       <begin>OPERATOR</begin>
       <token>DOUBLE_DOT</token>
@@ -95,5 +95,5 @@
 
     <!-- needs to be separate since what follows could be an operator name -->
-    <pattern expression='\.'>
+    <pattern expression='"."'>
       <begin>OPERATOR</begin>
       <token>@ASCII@</token>
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathModules.bgen.frag.diff?r1=1.1&r2=1.1.22.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathModules.bgen.frag?rev=1.1.22.1&content-type=text/vnd.viewcvs-markup

Index: XPathModules.bgen.frag
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/XPathModules.bgen.frag,v
retrieving revision 1.1
retrieving revision 1.1.22.1
diff -U2 -r1.1 -r1.1.22.1
--- XPathModules.bgen.frag	15 Sep 2001 18:20:48 -0000	1.1
+++ XPathModules.bgen.frag	4 Dec 2006 07:06:59 -0000	1.1.22.1
@@ -1,12 +1,29 @@
 <?xml version='1.0'?>
 <fragment>
-  <import from='Ft.Xml.XPath'>ParsedAbsoluteLocationPath</import>
-  <import from='Ft.Xml.XPath'>ParsedRelativeLocationPath</import>
-  <import from='Ft.Xml.XPath'>ParsedPredicateList</import>
-  <import from='Ft.Xml.XPath'>ParsedStep</import>
-  <import from='Ft.Xml.XPath'>ParsedAxisSpecifier</import>
-  <import from='Ft.Xml.XPath'>ParsedNodeTest</import>
-  <import from='Ft.Xml.XPath'>ParsedAbbreviatedAbsoluteLocationPath</import>
-  <import from='Ft.Xml.XPath'>ParsedAbbreviatedRelativeLocationPath</import>
-  <import from='Ft.Xml.XPath'>ParsedExpr</import>
+  <import from='Ft.Xml.XPath.ParsedAbsoluteLocationPath'>ParsedAbsoluteLocationPath</import>
+  <import from='Ft.Xml.XPath.ParsedRelativeLocationPath'>ParsedRelativeLocationPath</import>
+  <import from='Ft.Xml.XPath.ParsedPredicateList'>ParsedPredicateList</import>
+  <import from='Ft.Xml.XPath.ParsedStep'>ParsedStep</import>
+  <import from='Ft.Xml.XPath.ParsedStep'>ParsedAbbreviatedStep</import>
+  <import from='Ft.Xml.XPath.ParsedAxisSpecifier'>ParsedAxisSpecifier</import>
+  <import from='Ft.Xml.XPath.ParsedNodeTest'>ParsedNodeTest</import>
+  <import from='Ft.Xml.XPath.ParsedNodeTest'>ParsedNameTest</import>
+  <import from='Ft.Xml.XPath.ParsedNodeTest'>PrincipalTypeTest</import>
+  <import from='Ft.Xml.XPath.ParsedNodeTest'>LocalNameTest</import>
+  <import from='Ft.Xml.XPath.ParsedAbbreviatedAbsoluteLocationPath'>ParsedAbbreviatedAbsoluteLocationPath</import>
+  <import from='Ft.Xml.XPath.ParsedAbbreviatedRelativeLocationPath'>ParsedAbbreviatedRelativeLocationPath</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedVariableReferenceExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedLiteralExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedNLiteralExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedFunctionCallExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedUnionExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedPathExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedFilterExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedOrExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedAndExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedEqualityExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedRelationalExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedAdditiveExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedMultiplicativeExpr</import>
+  <import from='Ft.Xml.XPath.ParsedExpr'>ParsedUnaryExpr</import>
 </fragment>
\ No newline at end of file
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathParser.c.diff?r1=1.10&r2=1.10.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathParser.c?rev=1.10.2.1&content-type=text/vnd.viewcvs-markup

Index: XPathParser.c
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/XPathParser.c,v
retrieving revision 1.10
retrieving revision 1.10.2.1
diff -U2 -r1.10 -r1.10.2.1
--- XPathParser.c	17 Jan 2003 09:36:48 -0000	1.10
+++ XPathParser.c	4 Dec 2006 07:06:59 -0000	1.10.2.1
@@ -2,9 +2,42 @@
  * DO NOT EDIT THIS FILE!
  *
- * Parser generated by BisonGen on Fri Jan 17 01:45:24 2003.
+ * Parser generated by BisonGen on Wed Jan 11 15:37:20 2006.
  */
 
+#include "Python.h"
+#include "structmember.h"
+#include "../src/common.h"
+
+#define PROJECT_NAME "Ft.Xml.XPath"
+#define PARSER_NAME "XPathParser"
+#define MODULE_INITFUNC initXPathParserc
 
-#include <Python.h>
+/* modules required for action routines */
+static PyObject *ParsedAbsoluteLocationPath;
+static PyObject *ParsedRelativeLocationPath;
+static PyObject *ParsedPredicateList;
+static PyObject *ParsedStep;
+static PyObject *ParsedAbbreviatedStep;
+static PyObject *ParsedAxisSpecifier;
+static PyObject *ParsedNodeTest;
+static PyObject *ParsedNameTest;
+static PyObject *PrincipalTypeTest;
+static PyObject *LocalNameTest;
+static PyObject *ParsedAbbreviatedAbsoluteLocationPath;
+static PyObject *ParsedAbbreviatedRelativeLocationPath;
+static PyObject *ParsedVariableReferenceExpr;
+static PyObject *ParsedLiteralExpr;
+static PyObject *ParsedNLiteralExpr;
+static PyObject *ParsedFunctionCallExpr;
+static PyObject *ParsedUnionExpr;
+static PyObject *ParsedPathExpr;
+static PyObject *ParsedFilterExpr;
+static PyObject *ParsedOrExpr;
+static PyObject *ParsedAndExpr;
+static PyObject *ParsedEqualityExpr;
+static PyObject *ParsedRelationalExpr;
+static PyObject *ParsedAdditiveExpr;
+static PyObject *ParsedMultiplicativeExpr;
+static PyObject *ParsedUnaryExpr;
 
 /* token definitions */
@@ -83,155 +116,157 @@
 
 /* vector of line numbers and filename of all rules */
-static const char* const rule_info[] = {": line 0",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 5",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 8",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 15",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 24",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 34",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 41",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 44",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 55",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 62",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 72",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 83",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 90",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 104",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 121",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 131",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 149",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 158",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 169",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 185",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 201",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 208",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 224",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 241",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 250",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 263",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 272",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 285",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 292",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 301",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 313",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 322",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 332",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 339",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 352",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 368",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 380",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 399",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 406",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 409",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 424",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 427",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 430",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 441",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 457",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 460",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 474",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 477",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 492",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 495",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 510",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 513",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 528",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 531",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 566",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 569",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 580",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 595",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 598",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 631",
-                                      "Ft/Xml/XPath/XPathBase.bgen.frag: line 634",
-                                      };
+static const char* const rule_info[] = {
+    ": line 0",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 5",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 8",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 15",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 24",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 34",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 41",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 44",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 55",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 62",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 72",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 83",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 90",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 104",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 121",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 131",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 149",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 158",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 169",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 185",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 201",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 208",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 223",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 239",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 248",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 261",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 270",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 283",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 290",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 299",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 311",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 320",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 330",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 337",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 350",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 366",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 378",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 397",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 404",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 407",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 422",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 425",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 428",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 439",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 455",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 458",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 472",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 475",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 490",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 493",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 508",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 511",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 526",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 529",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 564",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 567",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 578",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 593",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 596",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 629",
+    "Ft/Xml/XPath/XPathBase.bgen.frag: line 632",
+};
 
 /* vector of string-names indexed by token number */
-static const char* const token_names[] = {"<EOF>",
-                                        "error",
-                                        "$undefined.",
-                                        "DOUBLE_DOT",
-                                        "DOUBLE_COLON",
-                                        "AT",
-                                        "LEFT_PAREN",
-                                        "LEFT_SQUARE",
-                                        "COMMA",
-                                        "LITERAL",
-                                        "NLITERAL",
-                                        "VARIABLE_REFERENCE",
-                                        "WILDCARD_NAME",
-                                        "MULTIPLY_OPERATOR",
-                                        "FUNCTION_NAME",
-                                        "DOUBLE_SLASH",
-                                        "NOT_EQUAL",
-                                        "LESS_THAN",
-                                        "GREATER_THAN",
-                                        "LESS_THAN_EQUAL",
-                                        "GREATER_THAN_EQUAL",
-                                        "OR",
-                                        "AND",
-                                        "DIV",
-                                        "MOD",
-                                        "COMMENT",
-                                        "TEXT",
-                                        "PROCESSING_INSTRUCTION",
-                                        "NODE",
-                                        "ANCESTOR",
-                                        "ANCESTOR_OR_SELF",
-                                        "ATTRIBUTE",
-                                        "CHILD",
-                                        "DESCENDANT",
-                                        "DESCENDANT_OR_SELF",
-                                        "FOLLOWING",
-                                        "FOLLOWING_SIBLING",
-                                        "NAMESPACE",
-                                        "PARENT",
-                                        "PRECEDING",
-                                        "PRECEDING_SIBLING",
-                                        "SELF",
-                                        "NODE_TYPE",
-                                        "AXIS_NAME",
-                                        "RELATIONAL_OP",
-                                        "EQUALITY_OP",
-                                        "/",
-                                        "(",
-                                        ")",
-                                        "[",
-                                        "]",
-                                        ".",
-                                        "@",
-                                        ",",
-                                        "|",
-                                        "+",
-                                        "-",
-                                        "locationPath",
-                                        "absoluteLocationPath",
-                                        "relativeLocationPath",
-                                        "step",
-                                        "predicateList",
-                                        "axisSpecifier",
-                                        "nodeTest",
-                                        "predicate",
-                                        "predicateExpr",
-                                        "abbreviatedAbsoluteLocationPath",
-                                        "abbreviatedRelativeLocationPath",
-                                        "abbreviatedStep",
-                                        "abbreviatedAxisSpecifier",
-                                        "expr",
-                                        "primaryExpr",
-                                        "functionCall",
-                                        "argumentList",
-                                        "argument",
-                                        "unionExpr",
-                                        "pathExpr",
-                                        "filterExpr",
-                                        "orExpr",
-                                        "andExpr",
-                                        "equalityExpr",
-                                        "relationalExpr",
-                                        "additiveExpr",
-                                        "multiplicativeExpr",
-                                        "unaryExpr",
-                                        "0",
-                                        };
+static const char* const token_names[] = {
+    "<EOF>",
+    "error",
+    "$undefined.",
+    "DOUBLE_DOT",
+    "DOUBLE_COLON",
+    "AT",
+    "LEFT_PAREN",
+    "LEFT_SQUARE",
+    "COMMA",
+    "LITERAL",
+    "NLITERAL",
+    "VARIABLE_REFERENCE",
+    "WILDCARD_NAME",
+    "MULTIPLY_OPERATOR",
+    "FUNCTION_NAME",
+    "DOUBLE_SLASH",
+    "NOT_EQUAL",
+    "LESS_THAN",
+    "GREATER_THAN",
+    "LESS_THAN_EQUAL",
+    "GREATER_THAN_EQUAL",
+    "OR",
+    "AND",
+    "DIV",
+    "MOD",
+    "COMMENT",
+    "TEXT",
+    "PROCESSING_INSTRUCTION",
+    "NODE",
+    "ANCESTOR",
+    "ANCESTOR_OR_SELF",
+    "ATTRIBUTE",
+    "CHILD",
+    "DESCENDANT",
+    "DESCENDANT_OR_SELF",
+    "FOLLOWING",
+    "FOLLOWING_SIBLING",
+    "NAMESPACE",
+    "PARENT",
+    "PRECEDING",
+    "PRECEDING_SIBLING",
+    "SELF",
+    "NODE_TYPE",
+    "AXIS_NAME",
+    "RELATIONAL_OP",
+    "EQUALITY_OP",
+    "/",
+    "(",
+    ")",
+    "[",
+    "]",
+    ".",
+    "@",
+    ",",
+    "|",
+    "+",
+    "-",
+    "locationPath",
+    "absoluteLocationPath",
+    "relativeLocationPath",
+    "step",
+    "predicateList",
+    "axisSpecifier",
+    "nodeTest",
+    "predicate",
+    "predicateExpr",
+    "abbreviatedAbsoluteLocationPath",
+    "abbreviatedRelativeLocationPath",
+    "abbreviatedStep",
+    "abbreviatedAxisSpecifier",
+    "expr",
+    "primaryExpr",
+    "functionCall",
+    "argumentList",
+    "argument",
+    "unionExpr",
+    "pathExpr",
+    "filterExpr",
+    "orExpr",
+    "andExpr",
+    "equalityExpr",
+    "relationalExpr",
+    "additiveExpr",
+    "multiplicativeExpr",
+    "unaryExpr",
+    "0",
+};
 
 /* symbol number of symbol that rule derives. */
@@ -307,26 +342,449 @@
 #define YYNTBASE 57
 
-/* modules required for action routines */
-static PyObject *ParsedAbsoluteLocationPath;
-static PyObject *ParsedRelativeLocationPath;
-static PyObject *ParsedPredicateList;
-static PyObject *ParsedStep;
-static PyObject *ParsedAxisSpecifier;
-static PyObject *ParsedNodeTest;
-static PyObject *ParsedAbbreviatedAbsoluteLocationPath;
-static PyObject *ParsedAbbreviatedRelativeLocationPath;
-static PyObject *ParsedExpr;
+#define LEXER_OP_FAILURE 0
+#define LEXER_OP_SUCCESS 1
+#define LEXER_OP_BOL 2
+#define LEXER_OP_EOL 3
+#define LEXER_OP_EOF 4
+#define LEXER_OP_ANY 5
+#define LEXER_OP_LITERAL 6
+#define LEXER_OP_NOT_LITERAL 7
+#define LEXER_OP_CHARSET 8
+#define LEXER_OP_NOT_CHARSET 9
+#define LEXER_OP_ASSERT 10
+#define LEXER_OP_BRANCH 11
+#define LEXER_OP_REPEAT 12
+#define LEXER_OP_REPEAT_RANGE 13
+
+#define LEXER_CHARSET_FAILURE 0
+#define LEXER_CHARSET_LITERAL 1
+#define LEXER_CHARSET_RANGE 2
+#define LEXER_CHARSET_SMALL 3
+#define LEXER_CHARSET_BIG 4
+
+#define LEXER_INITIAL 1
+#define LEXER_OPERATOR 2
+#define LEXER_START_STATE LEXER_INITIAL
+
+static unsigned char lexer_charsets[56][32] = {
+  { 0x00, 0x26, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x07,
+    0xFE, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF },
+  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0x7F, 0xFE, 0xFD, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x0F, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x31, 0xFC },
+  { 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xF8,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x40, 0xD7, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF,
+    0xFF, 0x7F, 0x7F, 0x54, 0xFD, 0xFF, 0x0F, 0x00 },
+  { 0xFE, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x9F, 0x19, 0xFF, 0xFF, 0xFF, 0xCF, 0x3F, 0x03 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x02,
+    0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0x07, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x07, 0xFE, 0x07, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7C,
+    0xFF, 0x7F, 0x2F, 0x00, 0x60, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x23, 0x00, 0x00, 0x00, 0xFF,
+    0x03, 0x00, 0x00, 0x00, 0xE0, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xC5, 0x03,
+    0x00, 0x00, 0x00, 0xB0, 0x03, 0x00, 0x03, 0x00 },
+  { 0xE0, 0x87, 0xF9, 0xFF, 0xFF, 0xFD, 0x6D, 0x03, 0x00, 0x00, 0x00, 0x5E,
+    0x00, 0x00, 0x1C, 0x00, 0xE0, 0xAF, 0xFB, 0xFF, 0xFF, 0xFD, 0xED, 0x23,
+    0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 },
+  { 0xE0, 0x9F, 0xF9, 0xFF, 0xFF, 0xFD, 0xCD, 0x23, 0x00, 0x00, 0x00, 0xB0,
+    0x03, 0x00, 0x00, 0x00, 0xE0, 0xC7, 0x3D, 0xD6, 0x18, 0xC7, 0xBF, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xEF, 0x03, 0x00, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xEF, 0x03,
+    0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x00 },
+  { 0xE0, 0xDF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x0D, 0x00, 0x3F, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x96, 0x25, 0xF0, 0xFE, 0xAE, 0x6C, 0x0D, 0x20,
+    0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0xFF, 0xFF,
+    0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+    0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00 },
+  { 0xED, 0xDA, 0x07, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x50, 0x31, 0x82,
+    0xAB, 0x62, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0xC9, 0x80, 0xF5,
+    0x07, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x02 },
+  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03 },
+  { 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0xFF, 0xAA,
+    0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0x5F,
+    0xDC, 0x1F, 0xCF, 0x0F, 0xFF, 0x1F, 0xDC, 0x1F },
+  { 0x00, 0x00, 0x00, 0x00, 0x40, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07 },
+  { 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x80, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0xC0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00,
+    0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFB, 0xFF, 0xFF, 0xBB,
+    0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xC0, 0xFF, 0x9F, 0x3D, 0x00, 0x00 },
+  { 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xFF, 0x3F, 0x1E, 0x00,
+    0x0C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0,
+    0x9F, 0x39, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x00 },
+  { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x87, 0x39, 0x00, 0x00,
+    0x00, 0x00, 0x03, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0,
+    0xBF, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x8F, 0x39, 0xC0, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
+    0xC7, 0x3D, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xDF, 0x3D, 0x60, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
+    0xDF, 0x3D, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xCF, 0x3D, 0x80, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x07, 0x80, 0x7F, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x1B,
+    0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xA0, 0xC2, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFE, 0xFF, 0xDF, 0x0F, 0xBF, 0xFE, 0xFF, 0x3F, 0xFE, 0x02,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xFF, 0x1F, 0x02, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70 },
+};
+
+static unsigned char lexer_blockmaps[5][256] = {
+  { 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0A, 0x0B, 0x0C, 0x0D,
+    0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x14, 0x15, 0x0A, 0x16, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x17, 0x18, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A },
+  { 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x1B, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+    0x19, 0x19, 0x19, 0x1C, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A },
+  { 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x1F, 0x0A, 0x0A, 0x20, 0x20, 0x21,
+    0x20, 0x22, 0x23, 0x24, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A },
+  { 0x0A, 0x0A, 0x0A, 0x25, 0x26, 0x27, 0x28, 0x0A, 0x0A, 0x29, 0x2A, 0x2B,
+    0x2C, 0x2D, 0x2E, 0x2F, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x30, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x31, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A },
+  { 0x32, 0x0A, 0x33, 0x34, 0x0A, 0x0A, 0x35, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x36, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x37, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
+    0x0A, 0x0A, 0x0A, 0x0A },
+};
+
+static const Py_UCS4 lexer_INITIAL_pattern_0[] = { 8, 4, 3, 1, 0, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_1[] = { 6, 58, 6, 58, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_2[] = { 6, 47, 6, 47, 1 };
 
-/* the expressions and information for each rule */
+static const Py_UCS4 lexer_INITIAL_pattern_3[] = { 11, 4, 6, 61, 1, 6, 
+  6, 33, 6, 61, 1, 0, 1 };
 
-/* the patterns will be created in the module init */
-static PyObject *patterns[] = {NULL, NULL, NULL};
-static const int pattern_actions[] = {2, 1, 275, 2, 1, 276, 2, 1, 267, 
-0, 0, 0, 1, 1, 0, 2, 2, 0, 2, 1, 258, 2, 1, 269, 2, 1, 299, 2, 1, 298, 
-2, 0, 296, 2, 0, 297, 2, 2, 263, 2, 2, 264, 2, 2, 265, 2, 0, 268, 2, 2, 
-266, 2, 2, 257, 2, 2, 0, 0, 0, 0, 2, 1, 0};
+static const Py_UCS4 lexer_INITIAL_pattern_4[] = { 11, 7, 8, 4, 3, 2, 0, 
+  1, 6, 6, 60, 6, 61, 1, 6, 6, 62, 6, 61, 1, 0, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_5[] = { 11, 10, 6, 110, 6, 111, 
+  6, 100, 6, 101, 1, 10, 6, 116, 6, 101, 6, 120, 6, 116, 1, 16, 6, 99, 
+  6, 111, 6, 109, 6, 109, 6, 101, 6, 110, 6, 116, 1, 46, 6, 112, 6, 114, 
+  6, 111, 6, 99, 6, 101, 6, 115, 6, 115, 6, 105, 6, 110, 6, 103, 6, 45, 
+  6, 105, 6, 110, 6, 115, 6, 116, 6, 114, 6, 117, 6, 99, 6, 116, 6, 105, 
+  6, 111, 6, 110, 1, 0, 10, 13, 12, 8, 0, 8, 4, 3, 0, 0, 1, 6, 40, 1, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_6[] = { 11, 4, 6, 95, 1, 18, 
+  11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 0, 12, 51, 0, 11, 
+  7, 8, 4, 3, 29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 
+  1, 0, 1, 7, 8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 1, 7, 8, 4, 4, 4, 0, 
+  1, 0, 1, 10, 15, 12, 8, 0, 8, 4, 3, 0, 0, 1, 6, 58, 6, 58, 1, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_7[] = { 11, 12, 6, 39, 12, 5, 
+  0, 7, 39, 1, 6, 39, 1, 12, 6, 34, 12, 5, 0, 7, 34, 1, 6, 34, 1, 0, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_8[] = { 11, 32, 12, 8, 1, 8, 
+  4, 4, 2, 0, 1, 13, 20, 0, 1, 6, 46, 13, 13, 0, 1, 12, 8, 1, 8, 4, 4, 
+  2, 0, 1, 1, 1, 1, 13, 6, 46, 12, 8, 1, 8, 4, 4, 2, 0, 1, 1, 0, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_9[] = { 6, 36, 13, 82, 0, 1, 
+  11, 4, 6, 95, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 
+  1, 0, 12, 51, 0, 11, 7, 8, 4, 3, 29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 
+  1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 7, 8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 
+  1, 7, 8, 4, 4, 4, 0, 1, 0, 1, 6, 58, 1, 11, 4, 6, 95, 1, 18, 11, 7, 8, 
+  4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 0, 12, 51, 0, 11, 7, 8, 4, 
+  3, 29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 
+  7, 8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 1, 7, 8, 4, 4, 4, 0, 1, 0, 1, 
+  1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_10[] = { 13, 82, 0, 1, 11, 4, 
+  6, 95, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 0, 
+  12, 51, 0, 11, 7, 8, 4, 3, 29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 
+  8, 4, 4, 1, 0, 1, 0, 1, 7, 8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 1, 7, 
+  8, 4, 4, 4, 0, 1, 0, 1, 6, 58, 1, 11, 4, 6, 95, 1, 18, 11, 7, 8, 4, 4, 
+  0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 0, 12, 51, 0, 11, 7, 8, 4, 3, 29, 
+  0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 7, 8, 4, 
+  4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 1, 7, 8, 4, 4, 4, 0, 1, 0, 1, 10, 13, 12, 
+  8, 0, 8, 4, 3, 0, 0, 1, 6, 40, 1, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_11[] = { 11, 4, 6, 42, 1, 82, 
+  11, 4, 6, 95, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 
+  1, 0, 12, 51, 0, 11, 7, 8, 4, 3, 29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 
+  1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 7, 8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 
+  1, 7, 8, 4, 4, 4, 0, 1, 0, 1, 6, 58, 6, 42, 1, 161, 13, 82, 0, 1, 11, 
+  4, 6, 95, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 
+  0, 12, 51, 0, 11, 7, 8, 4, 3, 29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 
+  7, 8, 4, 4, 1, 0, 1, 0, 1, 7, 8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 1, 
+  7, 8, 4, 4, 4, 0, 1, 0, 1, 6, 58, 1, 11, 4, 6, 95, 1, 18, 11, 7, 8, 4, 
+  4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 0, 12, 51, 0, 11, 7, 8, 4, 3, 
+  29, 0, 1, 18, 11, 7, 8, 4, 4, 0, 0, 1, 7, 8, 4, 4, 1, 0, 1, 0, 1, 7, 
+  8, 4, 4, 2, 0, 1, 7, 8, 4, 4, 3, 0, 1, 7, 8, 4, 4, 4, 0, 1, 0, 1, 1, 
+  0, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_12[] = { 6, 46, 6, 46, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_13[] = { 6, 46, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_14[] = { 12, 8, 1, 8, 4, 3, 
+  0, 0, 1, 1 };
+
+static const Py_UCS4 lexer_INITIAL_pattern_15[] = { 5, 1 };
+
+static const Py_UCS4 *lexer_INITIAL_patterns[] = {
+  lexer_INITIAL_pattern_0,
+  lexer_INITIAL_pattern_1,
+  lexer_INITIAL_pattern_2,
+  lexer_INITIAL_pattern_3,
+  lexer_INITIAL_pattern_4,
+  lexer_INITIAL_pattern_5,
+  lexer_INITIAL_pattern_6,
+  lexer_INITIAL_pattern_7,
+  lexer_INITIAL_pattern_8,
+  lexer_INITIAL_pattern_9,
+  lexer_INITIAL_pattern_10,
+  lexer_INITIAL_pattern_11,
+  lexer_INITIAL_pattern_12,
+  lexer_INITIAL_pattern_13,
+  lexer_INITIAL_pattern_14,
+  lexer_INITIAL_pattern_15,
+  NULL
+};
+
+static const Py_UCS4 lexer_OPERATOR_pattern_0[] = { 6, 111, 6, 114, 1 };
+
+static const Py_UCS4 lexer_OPERATOR_pattern_1[] = { 6, 97, 6, 110, 6, 100, 
+  1 };
+
+static const Py_UCS4 lexer_OPERATOR_pattern_2[] = { 11, 4, 6, 42, 1, 8, 
+  6, 109, 6, 111, 6, 100, 1, 8, 6, 100, 6, 105, 6, 118, 1, 0, 1 };
+
+static const Py_UCS4 lexer_OPERATOR_pattern_3[] = { 12, 8, 1, 8, 4, 3, 
+  0, 0, 1, 1 };
+
+static const Py_UCS4 lexer_OPERATOR_pattern_4[] = { 5, 1 };
+
+static const Py_UCS4 *lexer_OPERATOR_patterns[] = {
+  lexer_OPERATOR_pattern_0,
+  lexer_OPERATOR_pattern_1,
+  lexer_OPERATOR_pattern_2,
+  lexer_OPERATOR_pattern_3,
+  lexer_OPERATOR_pattern_4,
+  NULL
+};
+
+static const Py_UCS4 **lexer_patterns[] = {
+  NULL,
+  lexer_INITIAL_patterns,
+  lexer_OPERATOR_patterns
+};
 
-#if PY_MAJOR_VERSION < 2
-#error "Python 2.0 or later required"
+static const int lexer_INITIAL_actions[] = { 5, 6, 7, 8, 9, 10, 11, 12, 
+  13, 14, 15, 16, 17, 18, 19, 20 };
+
+static const int lexer_OPERATOR_actions[] = { 0, 1, 2, 3, 4 };
+
+static const int *lexer_actions[] = {
+  NULL,
+  lexer_INITIAL_actions,
+  lexer_OPERATOR_actions
+};
+
+#if PY_VERSION_HEX < 0x02020000 || !defined(Py_USING_UNICODE)
+#error "Python 2.2+ with unicode support required"
 #endif
 
@@ -336,8 +794,5 @@
 #define YYEOF 0
 #define YYINITDEPTH 1000
-
-#define LEXER_ACTION_SIZE 3
-#define LEXER_INITIAL 1
-
+#define LEXER_INITIAL_BACKTRACKS 20
 
 /* Parsing objects */
@@ -345,56 +800,54 @@
   PyObject_HEAD
   int verbose;
+  PyObject *dict;
 } parserobject;
 
 typedef struct {
   PyObject *text;
-  int position;
   int last;
-  int end;
   int state;
-} lexerobject;
-
+  Py_UNICODE *end;
+  Py_UNICODE *position;
 
-/* Forward Declarations */
-staticforward PyTypeObject ParserType;
+  /* backtracking stack */
+  int backtracks;
+  Py_UNICODE **positions;
+  int allocated;
+} lexerobject;
 
-static char *unicode_escape_slice(PyObject *, int, int);
 static int parser_yylex(parserobject *, lexerobject *, PyObject **);
-static void lexer_error(lexerobject *lexer);
+static lexerobject *lexer_new(PyObject *);
+static void lexer_free(lexerobject *);
+static int lexer_save_position(lexerobject *);
+static Py_UNICODE *lexer_restore_position(lexerobject *);
+static int lexer_charset(parserobject *, Py_UCS4 *, Py_UCS4, int);
+static int lexer_match(parserobject *, lexerobject *, Py_UCS4 *);
+static void lexer_error(lexerobject *);
+
+static char *unicode_escape(Py_UNICODE *, int);
 static PyObject *report_error(int state, PyObject *lval, lexerobject *lexer);
 static void print_reduce(int ruleno);
 static void print_state_stack(int *stack, int *end);
 
-
-/* Parser Creation */
-static char parserobject__doc__[] = "This object represents a generated parser.";
-
-static PyObject *newparserobject(int verbose)
-{
-  parserobject *po;
-
-  ParserType.ob_type = &PyType_Type;
-  po = PyObject_New(parserobject, &ParserType);
-  if (po == NULL) return NULL;
-  po->verbose = verbose;
-  return (PyObject *)po;
-}
-
 /* Parser Methods */
 
-static void parser_dealloc(register parserobject *self)
-{
-  PyObject_Del(self);
-}
+/* Attempt to use C99 variable argument macros for improved error detection
+ * (just in case). 
+ */
+#ifdef __STDC__ /* C99 conformance macro */
+#define TRACE(...) if (self->verbose > 0) PySys_WriteStderr(__VA_ARGS__)
+#define REGEX_TRACE(...) if (self->verbose > 1) PySys_WriteStderr(__VA_ARGS__)
+#else
+#define TRACE if (self->verbose > 0) PySys_WriteStderr
+#define REGEX_TRACE if (self->verbose > 1) PySys_WriteStderr
+#endif
 
-static char parser_parse__doc__[] = "\
+static char parse_doc[] = "\
 parse(string) -> object\n\
 Converts the given string to a parse tree and return the top-most\n\
 element of the tree.";
 
-static PyObject* parser_parse(register parserobject *self, PyObject *args)
+static PyObject* parser_parse(register parserobject *self, PyObject *text)
 {
-  PyObject *arg0;
-
   register int yystate;
   register int yyn;
@@ -412,18 +865,11 @@
   int yychar1 = 0;
 
-  lexerobject lexer;
-
-  if (!PyArg_ParseTuple(args, "O:parse", &arg0)) return NULL;
-
-  /* attempt to coerce given object to unicode using default rules */
-  /* existing unicode object is increfed, else new reference */
-  if (!(lexer.text = PyUnicode_FromObject(arg0))) return NULL;
+  lexerobject *lexer;
 
-  /* setup the lexer object */
-  lexer.end = PyUnicode_GET_SIZE(lexer.text);
-  lexer.position = lexer.last = 0;
-  lexer.state = LEXER_INITIAL;
+  lexer = lexer_new(text);
+  if (lexer == NULL)
+    return NULL;
 
-  if (self->verbose) PySys_WriteStderr("Starting parse\n");
+  TRACE("Starting parse\n");
 
   /* Initialize stack pointers
@@ -442,5 +888,5 @@
     *++state_ptr = yystate;
 
-    if (self->verbose) PySys_WriteStderr("Entering state %d\n", yystate);
+    TRACE("Entering state %d\n", yystate);
 
     /* Do appropriate processing given the current state. */
@@ -452,5 +898,5 @@
       yyn = default_action[yystate];
       if (yyn == 0) {
-        return report_error(yystate, yylval, &lexer);
+        return report_error(yystate, yylval, lexer);
       }
 
@@ -469,5 +915,5 @@
    * absoluteLocationPath: '/'
    */
-  yyval = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", Py_None);
+  yyval = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", Py_None);
   if (self->verbose) {
     fprintf(stderr, "--absoluteLocationPath(");
@@ -482,5 +928,5 @@
    * absoluteLocationPath: '/' relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--absoluteLocationPath(");
@@ -498,5 +944,5 @@
    * relativeLocationPath: relativeLocationPath '/' step
    */
-  yyval = PyObject_CallMethod(ParsedRelativeLocationPath, "ParsedRelativeLocationPath", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedRelativeLocationPath, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--relativeLocationPath(");
@@ -517,5 +963,5 @@
    * step: axisSpecifier nodeTest
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedStep", "OO", value_ptr[1], value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedStep, "OO", value_ptr[1], value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--step(");
@@ -533,5 +979,5 @@
    * step: axisSpecifier nodeTest predicateList
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedStep", "OOO", value_ptr[1], value_ptr[2], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedStep, "OOO", value_ptr[1], value_ptr[2], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--step(");
@@ -556,5 +1002,5 @@
   PyList_SET_ITEM(pred_list, 0, value_ptr[1]);
   Py_INCREF(value_ptr[1]);
-  yyval = PyObject_CallMethod(ParsedPredicateList, "ParsedPredicateList", "O", pred_list);
+  yyval = PyObject_CallFunction(ParsedPredicateList, "O", pred_list);
   Py_DECREF(pred_list);
   if (self->verbose) {
@@ -588,5 +1034,5 @@
    * axisSpecifier: AXIS_NAME DOUBLE_COLON
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--axisSpecifier(");
@@ -604,5 +1050,5 @@
    * nodeTest: WILDCARD_NAME
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNameTest", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNameTest, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -617,5 +1063,5 @@
    * nodeTest: NODE_TYPE '(' ')'
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNodeTest, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -636,5 +1082,5 @@
    * nodeTest: NODE_TYPE '(' LITERAL ')'
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedNodeTest, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -678,7 +1124,6 @@
    * abbreviatedAbsoluteLocationPath: DOUBLE_SLASH relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedAbbreviatedAbsoluteLocationPath,
-                           "ParsedAbbreviatedAbsoluteLocationPath",
-                           "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedAbsoluteLocationPath,
+                             "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAbsoluteLocationPath(");
@@ -693,10 +1138,9 @@
 }
 case 22: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 224
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 223
    * abbreviatedRelativeLocationPath: relativeLocationPath DOUBLE_SLASH step
    */
-  yyval = PyObject_CallMethod(ParsedAbbreviatedRelativeLocationPath,
-                           "ParsedAbbreviatedRelativeLocationPath",
-                           "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedRelativeLocationPath,
+                             "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedRelativeLocationPath(");
@@ -714,8 +1158,8 @@
 }
 case 23: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 241
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 239
    * abbreviatedStep: '.'
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 0);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 0);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedStep(");
@@ -727,8 +1171,8 @@
 }
 case 24: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 250
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 248
    * abbreviatedStep: DOUBLE_DOT
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 1);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 1);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedStep(");
@@ -740,8 +1184,8 @@
 }
 case 25: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 263
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 261
    * abbreviatedAxisSpecifier: '@'
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "attribute");
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "s", "attribute");
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAxisSpecifier(");
@@ -753,8 +1197,8 @@
 }
 case 26: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 272
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 270
    * abbreviatedAxisSpecifier:
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "child");
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "s", "child");
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAxisSpecifier(");
@@ -764,8 +1208,8 @@
 }
 case 28: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 292
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 290
    * primaryExpr: VARIABLE_REFERENCE
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedVariableReferenceExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedVariableReferenceExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -777,5 +1221,5 @@
 }
 case 29: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 301
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 299
    * primaryExpr: '(' expr ')'
    */
@@ -797,8 +1241,8 @@
 }
 case 30: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 313
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 311
    * primaryExpr: LITERAL
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedLiteralExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedLiteralExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -810,8 +1254,8 @@
 }
 case 31: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 322
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 320
    * primaryExpr: NLITERAL
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedNLiteralExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNLiteralExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -823,9 +1267,9 @@
 }
 case 33: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 339
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 337
    * functionCall: FUNCTION_NAME '(' ')'
    */
   PyObject *arg_list = PyList_New(0);
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedFunctionCallExpr", "OO", value_ptr[1], arg_list);
+  yyval = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", value_ptr[1], arg_list);
   Py_DECREF(arg_list);
   if (self->verbose) {
@@ -844,8 +1288,8 @@
 }
 case 34: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 352
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 350
    * functionCall: FUNCTION_NAME '(' argumentList ')'
    */
-  yyval = PyObject_CallMethod(ParsedExpr ,"ParsedFunctionCallExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--functionCall(");
@@ -866,5 +1310,5 @@
 }
 case 35: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 368
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 366
    * argumentList: argument
    */
@@ -882,5 +1326,5 @@
 }
 case 36: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 380
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 378
    * argumentList: argumentList ',' argument
    */
@@ -903,8 +1347,8 @@
 }
 case 39: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 409
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 407
    * unionExpr: unionExpr '|' pathExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedUnionExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedUnionExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--unionExpr(");
@@ -922,8 +1366,8 @@
 }
 case 42: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 430
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 428
    * pathExpr: filterExpr '/' relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 0, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedPathExpr, "iOO", 0, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--pathExpr(");
@@ -941,8 +1385,8 @@
 }
 case 43: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 441
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 439
    * pathExpr: filterExpr DOUBLE_SLASH relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedPathExpr, "iOO", 1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--pathExpr(");
@@ -960,8 +1404,8 @@
 }
 case 45: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 460
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 458
    * filterExpr: primaryExpr predicateList
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedFilterExpr", "OO", value_ptr[1], value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedFilterExpr, "OO", value_ptr[1], value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--filterExpr(");
@@ -976,8 +1420,8 @@
 }
 case 47: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 477
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 475
    * orExpr: orExpr OR andExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedOrExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedOrExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--orExpr(");
@@ -995,8 +1439,8 @@
 }
 case 49: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 495
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 493
    * andExpr: andExpr AND equalityExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAndExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAndExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--andExpr(");
@@ -1014,8 +1458,8 @@
 }
 case 51: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 513
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 511
    * equalityExpr: equalityExpr EQUALITY_OP relationalExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedEqualityExpr", "OOO", value_ptr[2], value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedEqualityExpr, "OOO", value_ptr[2], value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--equalityExpr(");
@@ -1033,5 +1477,5 @@
 }
 case 53: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 531
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 529
    * relationalExpr: relationalExpr RELATIONAL_OP additiveExpr
    */
@@ -1040,15 +1484,15 @@
     if (op[1] == '=') {
       /* less than or equal to */
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 1, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 1, value_ptr[1], value_ptr[3]);
     } else {
       /* less than */
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 0, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 0, value_ptr[1], value_ptr[3]);
     }
   } else if (op[1] == '=') {
     /* greater than or equal to */
-    yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 3, value_ptr[1], value_ptr[3]);
+    yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 3, value_ptr[1], value_ptr[3]);
   } else {
     /* greater than */
-    yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 2, value_ptr[1], value_ptr[3]);
+    yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 2, value_ptr[1], value_ptr[3]);
   }
   if (self->verbose) {
@@ -1067,8 +1511,8 @@
 }
 case 55: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 569
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 567
    * additiveExpr: additiveExpr '+' multiplicativeExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", 1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", 1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--additiveExpr(");
@@ -1086,8 +1530,8 @@
 }
 case 56: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 580
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 578
    * additiveExpr: additiveExpr '-' multiplicativeExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", -1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", -1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--additiveExpr(");
@@ -1105,5 +1549,5 @@
 }
 case 58: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 598
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 596
    * multiplicativeExpr: multiplicativeExpr MULTIPLY_OPERATOR unaryExpr
    */
@@ -1111,13 +1555,13 @@
   switch (*op) {
     case '*': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 0, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 0, value_ptr[1], value_ptr[3]);
       break;
     }
     case 'd': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 1, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 1, value_ptr[1], value_ptr[3]);
       break;
     }
     case 'm': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 2, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 2, value_ptr[1], value_ptr[3]);
       break;
     }
@@ -1138,8 +1582,8 @@
 }
 case 60: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 634
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 632
    * unaryExpr: '-' unionExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedUnaryExpr", "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedUnaryExpr, "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--unaryExpr(");
@@ -1155,7 +1599,7 @@
       }
       if (!yyval) {
-		Py_DECREF(lexer.text);
-		return NULL;
-	  }
+        lexer_free(lexer);
+        return NULL;
+      }
       *++value_ptr = yyval;
 
@@ -1181,6 +1625,6 @@
     /* yychar is either YYEMPTY, YYEOF or a valid token in external form */
     if (yychar == YYEMPTY) {
-      if (self->verbose) PySys_WriteStderr("Reading a token: ");
-      yychar = parser_yylex(self, &lexer, &yylval);
+      TRACE("Reading a token: ");
+      yychar = parser_yylex(self, lexer, &yylval);
     }
 
@@ -1189,15 +1633,13 @@
     if (yychar <= 0) {
       if (yychar == YYERROR) {
-        Py_DECREF(lexer.text);
+        lexer_free(lexer);
         return NULL;
       }
       /* This means end-of-input. */
       yychar1 = 0;
-      if (self->verbose) PySys_WriteStderr("Now at end of input.\n");
+      TRACE("Now at end of input.\n");
     } else {
       yychar1 = YYTRANSLATE(yychar);
-      if (self->verbose) {
-        PySys_WriteStderr("Next token is %d (%s)\n", yychar, token_names[yychar1]);
-      }
+      TRACE("Next token is %d (%s)\n", yychar, token_names[yychar1]);
       yyn += yychar1;
     }
@@ -1206,5 +1648,5 @@
       yyn = default_action[yystate];
       if (yyn == 0) {
-        return report_error(yystate, NULL, &lexer);
+        return report_error(yystate, NULL, lexer);
       }
 
@@ -1223,5 +1665,5 @@
    * absoluteLocationPath: '/'
    */
-  yyval = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", Py_None);
+  yyval = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", Py_None);
   if (self->verbose) {
     fprintf(stderr, "--absoluteLocationPath(");
@@ -1236,5 +1678,5 @@
    * absoluteLocationPath: '/' relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--absoluteLocationPath(");
@@ -1252,5 +1694,5 @@
    * relativeLocationPath: relativeLocationPath '/' step
    */
-  yyval = PyObject_CallMethod(ParsedRelativeLocationPath, "ParsedRelativeLocationPath", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedRelativeLocationPath, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--relativeLocationPath(");
@@ -1271,5 +1713,5 @@
    * step: axisSpecifier nodeTest
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedStep", "OO", value_ptr[1], value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedStep, "OO", value_ptr[1], value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--step(");
@@ -1287,5 +1729,5 @@
    * step: axisSpecifier nodeTest predicateList
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedStep", "OOO", value_ptr[1], value_ptr[2], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedStep, "OOO", value_ptr[1], value_ptr[2], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--step(");
@@ -1310,5 +1752,5 @@
   PyList_SET_ITEM(pred_list, 0, value_ptr[1]);
   Py_INCREF(value_ptr[1]);
-  yyval = PyObject_CallMethod(ParsedPredicateList, "ParsedPredicateList", "O", pred_list);
+  yyval = PyObject_CallFunction(ParsedPredicateList, "O", pred_list);
   Py_DECREF(pred_list);
   if (self->verbose) {
@@ -1342,5 +1784,5 @@
    * axisSpecifier: AXIS_NAME DOUBLE_COLON
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--axisSpecifier(");
@@ -1358,5 +1800,5 @@
    * nodeTest: WILDCARD_NAME
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNameTest", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNameTest, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -1371,5 +1813,5 @@
    * nodeTest: NODE_TYPE '(' ')'
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNodeTest, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -1390,5 +1832,5 @@
    * nodeTest: NODE_TYPE '(' LITERAL ')'
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedNodeTest, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -1432,7 +1874,6 @@
    * abbreviatedAbsoluteLocationPath: DOUBLE_SLASH relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedAbbreviatedAbsoluteLocationPath,
-                           "ParsedAbbreviatedAbsoluteLocationPath",
-                           "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedAbsoluteLocationPath,
+                             "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAbsoluteLocationPath(");
@@ -1447,10 +1888,9 @@
 }
 case 22: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 224
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 223
    * abbreviatedRelativeLocationPath: relativeLocationPath DOUBLE_SLASH step
    */
-  yyval = PyObject_CallMethod(ParsedAbbreviatedRelativeLocationPath,
-                           "ParsedAbbreviatedRelativeLocationPath",
-                           "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedRelativeLocationPath,
+                             "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedRelativeLocationPath(");
@@ -1468,8 +1908,8 @@
 }
 case 23: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 241
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 239
    * abbreviatedStep: '.'
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 0);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 0);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedStep(");
@@ -1481,8 +1921,8 @@
 }
 case 24: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 250
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 248
    * abbreviatedStep: DOUBLE_DOT
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 1);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 1);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedStep(");
@@ -1494,8 +1934,8 @@
 }
 case 25: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 263
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 261
    * abbreviatedAxisSpecifier: '@'
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "attribute");
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "s", "attribute");
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAxisSpecifier(");
@@ -1507,8 +1947,8 @@
 }
 case 26: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 272
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 270
    * abbreviatedAxisSpecifier:
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "child");
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "s", "child");
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAxisSpecifier(");
@@ -1518,8 +1958,8 @@
 }
 case 28: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 292
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 290
    * primaryExpr: VARIABLE_REFERENCE
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedVariableReferenceExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedVariableReferenceExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -1531,5 +1971,5 @@
 }
 case 29: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 301
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 299
    * primaryExpr: '(' expr ')'
    */
@@ -1551,8 +1991,8 @@
 }
 case 30: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 313
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 311
    * primaryExpr: LITERAL
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedLiteralExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedLiteralExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -1564,8 +2004,8 @@
 }
 case 31: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 322
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 320
    * primaryExpr: NLITERAL
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedNLiteralExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNLiteralExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -1577,9 +2017,9 @@
 }
 case 33: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 339
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 337
    * functionCall: FUNCTION_NAME '(' ')'
    */
   PyObject *arg_list = PyList_New(0);
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedFunctionCallExpr", "OO", value_ptr[1], arg_list);
+  yyval = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", value_ptr[1], arg_list);
   Py_DECREF(arg_list);
   if (self->verbose) {
@@ -1598,8 +2038,8 @@
 }
 case 34: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 352
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 350
    * functionCall: FUNCTION_NAME '(' argumentList ')'
    */
-  yyval = PyObject_CallMethod(ParsedExpr ,"ParsedFunctionCallExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--functionCall(");
@@ -1620,5 +2060,5 @@
 }
 case 35: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 368
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 366
    * argumentList: argument
    */
@@ -1636,5 +2076,5 @@
 }
 case 36: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 380
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 378
    * argumentList: argumentList ',' argument
    */
@@ -1657,8 +2097,8 @@
 }
 case 39: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 409
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 407
    * unionExpr: unionExpr '|' pathExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedUnionExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedUnionExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--unionExpr(");
@@ -1676,8 +2116,8 @@
 }
 case 42: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 430
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 428
    * pathExpr: filterExpr '/' relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 0, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedPathExpr, "iOO", 0, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--pathExpr(");
@@ -1695,8 +2135,8 @@
 }
 case 43: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 441
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 439
    * pathExpr: filterExpr DOUBLE_SLASH relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedPathExpr, "iOO", 1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--pathExpr(");
@@ -1714,8 +2154,8 @@
 }
 case 45: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 460
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 458
    * filterExpr: primaryExpr predicateList
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedFilterExpr", "OO", value_ptr[1], value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedFilterExpr, "OO", value_ptr[1], value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--filterExpr(");
@@ -1730,8 +2170,8 @@
 }
 case 47: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 477
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 475
    * orExpr: orExpr OR andExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedOrExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedOrExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--orExpr(");
@@ -1749,8 +2189,8 @@
 }
 case 49: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 495
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 493
    * andExpr: andExpr AND equalityExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAndExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAndExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--andExpr(");
@@ -1768,8 +2208,8 @@
 }
 case 51: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 513
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 511
    * equalityExpr: equalityExpr EQUALITY_OP relationalExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedEqualityExpr", "OOO", value_ptr[2], value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedEqualityExpr, "OOO", value_ptr[2], value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--equalityExpr(");
@@ -1787,5 +2227,5 @@
 }
 case 53: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 531
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 529
    * relationalExpr: relationalExpr RELATIONAL_OP additiveExpr
    */
@@ -1794,15 +2234,15 @@
     if (op[1] == '=') {
       /* less than or equal to */
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 1, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 1, value_ptr[1], value_ptr[3]);
     } else {
       /* less than */
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 0, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 0, value_ptr[1], value_ptr[3]);
     }
   } else if (op[1] == '=') {
     /* greater than or equal to */
-    yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 3, value_ptr[1], value_ptr[3]);
+    yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 3, value_ptr[1], value_ptr[3]);
   } else {
     /* greater than */
-    yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 2, value_ptr[1], value_ptr[3]);
+    yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 2, value_ptr[1], value_ptr[3]);
   }
   if (self->verbose) {
@@ -1821,8 +2261,8 @@
 }
 case 55: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 569
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 567
    * additiveExpr: additiveExpr '+' multiplicativeExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", 1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", 1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--additiveExpr(");
@@ -1840,8 +2280,8 @@
 }
 case 56: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 580
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 578
    * additiveExpr: additiveExpr '-' multiplicativeExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", -1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", -1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--additiveExpr(");
@@ -1859,5 +2299,5 @@
 }
 case 58: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 598
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 596
    * multiplicativeExpr: multiplicativeExpr MULTIPLY_OPERATOR unaryExpr
    */
@@ -1865,13 +2305,13 @@
   switch (*op) {
     case '*': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 0, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 0, value_ptr[1], value_ptr[3]);
       break;
     }
     case 'd': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 1, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 1, value_ptr[1], value_ptr[3]);
       break;
     }
     case 'm': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 2, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 2, value_ptr[1], value_ptr[3]);
       break;
     }
@@ -1892,8 +2332,8 @@
 }
 case 60: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 634
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 632
    * unaryExpr: '-' unionExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedUnaryExpr", "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedUnaryExpr, "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--unaryExpr(");
@@ -1909,7 +2349,7 @@
       }
       if (!yyval) {
-		Py_DECREF(lexer.text);
-		return NULL;
-	  }
+        lexer_free(lexer);
+        return NULL;
+      }
       *++value_ptr = yyval;
 
@@ -1956,5 +2396,5 @@
    * absoluteLocationPath: '/'
    */
-  yyval = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", Py_None);
+  yyval = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", Py_None);
   if (self->verbose) {
     fprintf(stderr, "--absoluteLocationPath(");
@@ -1969,5 +2409,5 @@
    * absoluteLocationPath: '/' relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedAbsoluteLocationPath, "ParsedAbsoluteLocationPath", "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedAbsoluteLocationPath, "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--absoluteLocationPath(");
@@ -1985,5 +2425,5 @@
    * relativeLocationPath: relativeLocationPath '/' step
    */
-  yyval = PyObject_CallMethod(ParsedRelativeLocationPath, "ParsedRelativeLocationPath", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedRelativeLocationPath, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--relativeLocationPath(");
@@ -2004,5 +2444,5 @@
    * step: axisSpecifier nodeTest
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedStep", "OO", value_ptr[1], value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedStep, "OO", value_ptr[1], value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--step(");
@@ -2020,5 +2460,5 @@
    * step: axisSpecifier nodeTest predicateList
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedStep", "OOO", value_ptr[1], value_ptr[2], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedStep, "OOO", value_ptr[1], value_ptr[2], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--step(");
@@ -2043,5 +2483,5 @@
   PyList_SET_ITEM(pred_list, 0, value_ptr[1]);
   Py_INCREF(value_ptr[1]);
-  yyval = PyObject_CallMethod(ParsedPredicateList, "ParsedPredicateList", "O", pred_list);
+  yyval = PyObject_CallFunction(ParsedPredicateList, "O", pred_list);
   Py_DECREF(pred_list);
   if (self->verbose) {
@@ -2075,5 +2515,5 @@
    * axisSpecifier: AXIS_NAME DOUBLE_COLON
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--axisSpecifier(");
@@ -2091,5 +2531,5 @@
    * nodeTest: WILDCARD_NAME
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNameTest", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNameTest, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -2104,5 +2544,5 @@
    * nodeTest: NODE_TYPE '(' ')'
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNodeTest, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -2123,5 +2563,5 @@
    * nodeTest: NODE_TYPE '(' LITERAL ')'
    */
-  yyval = PyObject_CallMethod(ParsedNodeTest, "ParsedNodeTest", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedNodeTest, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--nodeTest(");
@@ -2165,7 +2605,6 @@
    * abbreviatedAbsoluteLocationPath: DOUBLE_SLASH relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedAbbreviatedAbsoluteLocationPath,
-                           "ParsedAbbreviatedAbsoluteLocationPath",
-                           "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedAbsoluteLocationPath,
+                             "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAbsoluteLocationPath(");
@@ -2180,10 +2619,9 @@
 }
 case 22: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 224
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 223
    * abbreviatedRelativeLocationPath: relativeLocationPath DOUBLE_SLASH step
    */
-  yyval = PyObject_CallMethod(ParsedAbbreviatedRelativeLocationPath,
-                           "ParsedAbbreviatedRelativeLocationPath",
-                           "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedRelativeLocationPath,
+                             "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedRelativeLocationPath(");
@@ -2201,8 +2639,8 @@
 }
 case 23: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 241
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 239
    * abbreviatedStep: '.'
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 0);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 0);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedStep(");
@@ -2214,8 +2652,8 @@
 }
 case 24: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 250
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 248
    * abbreviatedStep: DOUBLE_DOT
    */
-  yyval = PyObject_CallMethod(ParsedStep, "ParsedAbbreviatedStep", "i", 1);
+  yyval = PyObject_CallFunction(ParsedAbbreviatedStep, "i", 1);
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedStep(");
@@ -2227,8 +2665,8 @@
 }
 case 25: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 263
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 261
    * abbreviatedAxisSpecifier: '@'
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "attribute");
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "s", "attribute");
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAxisSpecifier(");
@@ -2240,8 +2678,8 @@
 }
 case 26: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 272
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 270
    * abbreviatedAxisSpecifier:
    */
-  yyval = PyObject_CallMethod(ParsedAxisSpecifier, "ParsedAxisSpecifier", "s", "child");
+  yyval = PyObject_CallFunction(ParsedAxisSpecifier, "s", "child");
   if (self->verbose) {
     fprintf(stderr, "--abbreviatedAxisSpecifier(");
@@ -2251,8 +2689,8 @@
 }
 case 28: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 292
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 290
    * primaryExpr: VARIABLE_REFERENCE
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedVariableReferenceExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedVariableReferenceExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -2264,5 +2702,5 @@
 }
 case 29: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 301
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 299
    * primaryExpr: '(' expr ')'
    */
@@ -2284,8 +2722,8 @@
 }
 case 30: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 313
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 311
    * primaryExpr: LITERAL
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedLiteralExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedLiteralExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -2297,8 +2735,8 @@
 }
 case 31: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 322
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 320
    * primaryExpr: NLITERAL
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedNLiteralExpr", "O", value_ptr[1]);
+  yyval = PyObject_CallFunction(ParsedNLiteralExpr, "O", value_ptr[1]);
   if (self->verbose) {
     fprintf(stderr, "--primaryExpr(");
@@ -2310,9 +2748,9 @@
 }
 case 33: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 339
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 337
    * functionCall: FUNCTION_NAME '(' ')'
    */
   PyObject *arg_list = PyList_New(0);
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedFunctionCallExpr", "OO", value_ptr[1], arg_list);
+  yyval = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", value_ptr[1], arg_list);
   Py_DECREF(arg_list);
   if (self->verbose) {
@@ -2331,8 +2769,8 @@
 }
 case 34: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 352
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 350
    * functionCall: FUNCTION_NAME '(' argumentList ')'
    */
-  yyval = PyObject_CallMethod(ParsedExpr ,"ParsedFunctionCallExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedFunctionCallExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--functionCall(");
@@ -2353,5 +2791,5 @@
 }
 case 35: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 368
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 366
    * argumentList: argument
    */
@@ -2369,5 +2807,5 @@
 }
 case 36: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 380
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 378
    * argumentList: argumentList ',' argument
    */
@@ -2390,8 +2828,8 @@
 }
 case 39: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 409
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 407
    * unionExpr: unionExpr '|' pathExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedUnionExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedUnionExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--unionExpr(");
@@ -2409,8 +2847,8 @@
 }
 case 42: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 430
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 428
    * pathExpr: filterExpr '/' relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 0, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedPathExpr, "iOO", 0, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--pathExpr(");
@@ -2428,8 +2866,8 @@
 }
 case 43: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 441
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 439
    * pathExpr: filterExpr DOUBLE_SLASH relativeLocationPath
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedPathExpr", "iOO", 1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedPathExpr, "iOO", 1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--pathExpr(");
@@ -2447,8 +2885,8 @@
 }
 case 45: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 460
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 458
    * filterExpr: primaryExpr predicateList
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedFilterExpr", "OO", value_ptr[1], value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedFilterExpr, "OO", value_ptr[1], value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--filterExpr(");
@@ -2463,8 +2901,8 @@
 }
 case 47: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 477
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 475
    * orExpr: orExpr OR andExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedOrExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedOrExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--orExpr(");
@@ -2482,8 +2920,8 @@
 }
 case 49: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 495
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 493
    * andExpr: andExpr AND equalityExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAndExpr", "OO", value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAndExpr, "OO", value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--andExpr(");
@@ -2501,8 +2939,8 @@
 }
 case 51: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 513
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 511
    * equalityExpr: equalityExpr EQUALITY_OP relationalExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedEqualityExpr", "OOO", value_ptr[2], value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedEqualityExpr, "OOO", value_ptr[2], value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--equalityExpr(");
@@ -2520,5 +2958,5 @@
 }
 case 53: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 531
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 529
    * relationalExpr: relationalExpr RELATIONAL_OP additiveExpr
    */
@@ -2527,15 +2965,15 @@
     if (op[1] == '=') {
       /* less than or equal to */
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 1, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 1, value_ptr[1], value_ptr[3]);
     } else {
       /* less than */
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 0, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 0, value_ptr[1], value_ptr[3]);
     }
   } else if (op[1] == '=') {
     /* greater than or equal to */
-    yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 3, value_ptr[1], value_ptr[3]);
+    yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 3, value_ptr[1], value_ptr[3]);
   } else {
     /* greater than */
-    yyval = PyObject_CallMethod(ParsedExpr, "ParsedRelationalExpr", "lOO", 2, value_ptr[1], value_ptr[3]);
+    yyval = PyObject_CallFunction(ParsedRelationalExpr, "lOO", 2, value_ptr[1], value_ptr[3]);
   }
   if (self->verbose) {
@@ -2554,8 +2992,8 @@
 }
 case 55: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 569
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 567
    * additiveExpr: additiveExpr '+' multiplicativeExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", 1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", 1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--additiveExpr(");
@@ -2573,8 +3011,8 @@
 }
 case 56: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 580
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 578
    * additiveExpr: additiveExpr '-' multiplicativeExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedAdditiveExpr", "iOO", -1, value_ptr[1], value_ptr[3]);
+  yyval = PyObject_CallFunction(ParsedAdditiveExpr, "iOO", -1, value_ptr[1], value_ptr[3]);
   if (self->verbose) {
     fprintf(stderr, "--additiveExpr(");
@@ -2592,5 +3030,5 @@
 }
 case 58: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 598
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 596
    * multiplicativeExpr: multiplicativeExpr MULTIPLY_OPERATOR unaryExpr
    */
@@ -2598,13 +3036,13 @@
   switch (*op) {
     case '*': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 0, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 0, value_ptr[1], value_ptr[3]);
       break;
     }
     case 'd': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 1, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 1, value_ptr[1], value_ptr[3]);
       break;
     }
     case 'm': {
-      yyval = PyObject_CallMethod(ParsedExpr, "ParsedMultiplicativeExpr", "lOO", 2, value_ptr[1], value_ptr[3]);
+      yyval = PyObject_CallFunction(ParsedMultiplicativeExpr, "lOO", 2, value_ptr[1], value_ptr[3]);
       break;
     }
@@ -2625,8 +3063,8 @@
 }
 case 60: {
-  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 634
+  /* from Ft/Xml/XPath/XPathBase.bgen.frag, line 632
    * unaryExpr: '-' unionExpr
    */
-  yyval = PyObject_CallMethod(ParsedExpr, "ParsedUnaryExpr", "O", value_ptr[2]);
+  yyval = PyObject_CallFunction(ParsedUnaryExpr, "O", value_ptr[2]);
   if (self->verbose) {
     fprintf(stderr, "--unaryExpr(");
@@ -2642,7 +3080,7 @@
       }
       if (!yyval) {
-		Py_DECREF(lexer.text);
-		return NULL;
-	  }
+        lexer_free(lexer);
+        return NULL;
+      }
       *++value_ptr = yyval;
 
@@ -2663,16 +3101,14 @@
     } else if (yyn == YYFINAL) {
       /* Hooray!  Process complete. */
-      Py_DECREF(lexer.text);
+      lexer_free(lexer);
       return value_ptr[-1];
     } else if (yyn <= 0) {
       /* Now it is either 0 or YYFLAG */
-      return report_error(yystate, yylval, &lexer);
+      return report_error(yystate, yylval, lexer);
     }
 
     /* Shift the lookahead token. */
 
-    if (self->verbose) {
-      PySys_WriteStderr("Shifting token %d (%s), ", yychar, token_names[yychar1]);
-    }
+    TRACE("Shifting token %d (%s), ", yychar, token_names[yychar1]);
 
     if (yychar != YYEOF) {
@@ -2688,69 +3124,946 @@
   /* should never get here */
   Py_INCREF(Py_None);
-  Py_DECREF(lexer.text);
+  lexer_free(lexer);
   return Py_None;
 }
 
-static int parser_yylex(parserobject *self, lexerobject *lexer, PyObject **yylval)
+/** lexer routines ****************************************************/
+
+static lexerobject *lexer_new(PyObject *text)
 {
-  int yychar = YYEMPTY;
+  lexerobject *lexer;
 
-  while (lexer->last < lexer->end) {
-    PyObject *match, *groupdict;
-    PyObject *key;
-    int pos;
-    const int *action;
-
-    lexer->position = lexer->last;
-    match = PyObject_CallMethod(patterns[lexer->state], "match", "Oi",
-                                lexer->text, lexer->position);
-    if (match == Py_None) {
-      Py_DECREF(match);
-      lexer_error(lexer);
+  lexer = PyMem_New(lexerobject, 1);
+  if (lexer == NULL) {
+    PyErr_NoMemory();
+    return NULL;
+  }
+
+  /* attempt to coerce given object to unicode using default rules */
+  lexer->text = PyUnicode_FromObject(text);
+  if (lexer->text == NULL) {
+    PyMem_Free(lexer);
+    return NULL;
+  }
+  lexer->position = PyUnicode_AS_UNICODE(lexer->text);
+  lexer->end = lexer->position + PyUnicode_GET_SIZE(lexer->text);
+  lexer->state = LEXER_START_STATE;
+
+  /* create initial backtracking stack */
+  lexer->positions = PyMem_New(Py_UNICODE *, LEXER_INITIAL_BACKTRACKS);
+  if (lexer->positions == NULL) {
+    PyErr_NoMemory();
+    Py_DECREF(lexer->text);
+    PyMem_Free(lexer);
+    return NULL;
+  }
+  lexer->allocated = LEXER_INITIAL_BACKTRACKS;
+  lexer->backtracks = 0;
+  return lexer;
+}
+
+static void lexer_free(lexerobject *lexer)
+{
+  PyMem_Free(lexer->positions);
+  Py_DECREF(lexer->text);
+  PyMem_Free(lexer);
+}
+
+static int lexer_save_position(lexerobject *lexer) {
+  Py_UNICODE **positions;
+  size_t new_allocated;
+  int allocated, newsize;
+
+  /* Bypass realloc() when a previous overallocation is large enough
+     to accommodate the newsize.
+  */
+  newsize = lexer->backtracks + 1;
+  allocated = lexer->allocated;
+  positions = lexer->positions;
+  if (newsize >= allocated) {
+    /* This over-allocates proportional to the list size, making room
+     * for additional growth.  The over-allocation is mild, but is
+     * enough to give linear-time amortized behavior over a long
+     * sequence of appends() in the presence of a poorly-performing
+     * system realloc().
+     * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
+     */
+    new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
+    if (PyMem_Resize(positions, Py_UNICODE *, new_allocated) == NULL) {
+      PyErr_NoMemory();
+      return -1;
+    }
+    lexer->allocated = new_allocated;
+    lexer->positions = positions;
+  }
+  lexer->positions[lexer->backtracks] = lexer->position;
+  lexer->backtracks = newsize;
+  return 0;
+}
+
+static Py_UNICODE *lexer_restore_position(lexerobject *lexer) {
+  assert(lexer->backtracks > 0);
+  lexer->position = lexer->positions[--lexer->backtracks];
+  return lexer->position;
+}
+
+static int lexer_charset(parserobject *self, Py_UCS4 *set, Py_UCS4 ch,
+			 int ok)
+{
+  unsigned char *charset;
+
+  /* check if character is a member of the given set */
+  /* Note, the tests are stored sorted to allow for quick exits */
+
+  for (;;) {
+    switch (*set++) {
+
+    case LEXER_CHARSET_LITERAL:
+      /* <LITERAL> <code> */
+      REGEX_TRACE("CHARSET_LITERAL, %d == %d\n", ch, set[0]);
+      if (ch < set[0])
+        return !ok;
+      else if ((Py_UCS4)ch == set[0])
+        return ok;
+      set++;
+      break;
+
+    case LEXER_CHARSET_RANGE:
+      /* <RANGE> <lower> <upper> */
+      REGEX_TRACE("CHARSET_RANGE, %d <= %d <= %d\n", set[0], ch, set[1]);
+      if (ch < set[0])
+        return !ok;
+      else if (ch <= set[1])
+        return ok;
+      set += 2;
+      break;
+
+    case LEXER_CHARSET_SMALL:
+      /* <SMALL> <charset index> */
+      REGEX_TRACE("CHARSET_SMALL, index=%d\n", set[0]);
+      charset = lexer_charsets[*set++];
+      if (ch < 256 && (charset[ch >> 3] & (1 << (ch & 7))))
+        return ok;
+      break;
+
+    case LEXER_CHARSET_BIG:
+      /* <BIG> <blockmap index> */
+      REGEX_TRACE("CHARSET_BIG, index=%d\n", set[0]);
+      charset = lexer_charsets[lexer_blockmaps[*set++][ch >> 8]];
+      if (ch < 65536 && charset[(ch & 255) >> 3] & (1 << (ch & 7)))
+        return ok;
+      break;
+
+    case LEXER_CHARSET_FAILURE:
+      /* nothing matched in charset */
+      REGEX_TRACE("CHARSET_FAILURE\n");
+      return !ok;
+
+    default:
+      REGEX_TRACE("**INTERNAL CHARSET ERROR**\n");
       return -1;
     }
+  }
+}
+
+/* return values:
+   1 -> sucessful match,
+   0 -> no match,
+   -1 -> error,
+*/
+
+#ifdef Py_UNICODE_WIDE
+#define GET_CHAR_AND_ADVANCE() ch = *ptr++;
+#else
+#define GET_CHAR_AND_ADVANCE()                                          \
+  if ((0xD800 <= ptr[0] && ptr[0] <= 0xDBFF) &&                         \
+      (0xDC00 <= ptr[1] && ptr[1] <= 0xDFFF)) {                         \
+    ch = (((ptr[0] & 0x03FF) << 10) | (ptr[1] & 0x03FF)) + 0x00010000;  \
+    ptr += 2;                                                           \
+  } else {                                                              \
+    ch = *ptr++;                                                        \
+  }
+#endif  
+    
+static int lexer_match(parserobject *self, lexerobject *lexer, 
+		       Py_UCS4 *pattern)
+{
+  Py_UNICODE *ptr = lexer->position;
+  Py_UNICODE *end;
+  Py_UCS4 ch;
+  int i, count;
+
+  REGEX_TRACE("LEXER_MATCH, position %" YY_FORMAT_SIZE_T "d\n",
+              lexer->position - PyUnicode_AS_UNICODE(lexer->text));
+
+  while (1) {
+    switch (*pattern++) {
 
-    groupdict = PyObject_CallMethod(match, "groupdict", NULL);
-    Py_DECREF(match);
-    pos = 0;
-    action = NULL;
-    while (PyDict_Next(groupdict, &pos, &key, yylval)) {
-      /* sre only allows strings as group names */
-      if (*yylval != Py_None) {
-        lexer->last += PyUnicode_GET_SIZE(*yylval);
-        pos = atoi(PyString_AsString(key) + 1);
-        action = pattern_actions + (pos * LEXER_ACTION_SIZE);
-        Py_INCREF(*yylval);
+    case LEXER_OP_FAILURE:
+      /* immediate failure */
+      REGEX_TRACE("OP_FAILURE\n");
+      return 0;
+
+    case LEXER_OP_SUCCESS:
+      /* end of pattern */
+      REGEX_TRACE("OP_SUCCESS\n");
+      lexer->position = ptr;
+      return 1;
+        
+    case LEXER_OP_BOL:
+      /* beginning of line */
+      /* <BOL> */
+      REGEX_TRACE("OP_BOL\n");
+      if (ptr == PyUnicode_AS_UNICODE(lexer->text) || ptr[-1] == '\n') 
         break;
+      return 0;
+
+    case LEXER_OP_EOL:
+      /* end of line */
+      /* <EOL> */
+      REGEX_TRACE("OP_EOL\n");
+      if (ptr >= lexer->end || ptr[0] == '\n') break;
+      return 0;
+            
+    case LEXER_OP_EOF:
+      /* end of file */
+      /* <EOF> */
+      REGEX_TRACE("OP_EOF\n");
+      if (ptr >= lexer->end) break;
+      return 0;
+
+    case LEXER_OP_ANY:
+      /* match anything (except a newline) */
+      /* <ANY> */
+      REGEX_TRACE("OP_ANY\n");
+      if (ptr >= lexer->end || ptr[0] == '\n')
+        return 0;
+      ptr++;
+      break;
+
+    case LEXER_OP_LITERAL:
+      /* match literal character */
+      /* <LITERAL> <code> */
+      if (ptr >= lexer->end)
+        return 0;
+      GET_CHAR_AND_ADVANCE();
+      REGEX_TRACE("OP_LITERAL, %d == %d\n", ch, pattern[0]);
+      if (ch != pattern[0])
+        return 0;
+      pattern++;
+      break;
+
+    case LEXER_OP_NOT_LITERAL:
+      /* match anything that is not literal character */
+      /* <NOT_LITERAL> <code> */
+      if (ptr >= lexer->end)
+        return 0;
+      GET_CHAR_AND_ADVANCE();
+      REGEX_TRACE("OP_NOT_LITERAL, %d != %d\n", ch, pattern[0]);
+      if (ch == pattern[0])
+        return 0;
+      pattern++;
+      break;
+
+    case LEXER_OP_CHARSET:
+      /* match set member */
+      /* <CHARSET> <skip> <set> */
+      if (ptr >= lexer->end)
+        return 0;
+      GET_CHAR_AND_ADVANCE();
+      REGEX_TRACE("OP_CHARSET, skip %d\n", pattern[0]);
+      i = lexer_charset(self, pattern + 1, ch, 1);
+      if (i <= 0)
+        return i;
+
+      pattern += pattern[0];
+      break;
+            
+    case LEXER_OP_NOT_CHARSET:
+      /* match set non-member */
+      /* <NOT_CHARSET> <skip> <set> */
+      if (ptr >= lexer->end)
+        return 0;
+      GET_CHAR_AND_ADVANCE();
+      REGEX_TRACE("OP_NOT_CHARSET, skip %d\n", pattern[0]);
+      i = lexer_charset(self, pattern + 1, ch, 0);
+      if (i <= 0)
+        return i;
+
+      pattern += pattern[0];
+      break;
+            
+    case LEXER_OP_ASSERT:
+      /* lookahead assertion */
+      /* <ASSERT> <skip> <pattern> */
+      REGEX_TRACE("OP_ASSERT, skip %d\n", pattern[0]);
+      lexer->position = ptr;
+      i = lexer_match(self, lexer, pattern + 1);
+      if (i <= 0)
+        return i;
+
+      pattern += pattern[0];
+      break;
+
+    case LEXER_OP_BRANCH:
+      /* alternation */
+      /* <BRANCH> <skip0> <code0> <skip1> <code1> ... <NULL> */
+
+      end = NULL;
+      count = 0;
+      while (pattern[0]) {
+        /* reset start position each time through */
+	REGEX_TRACE("OP_BRANCH %d, skip %d\n", count++, pattern[0]);
+        lexer->position = ptr;
+        
+        i = lexer_match(self, lexer, pattern + 1);
+        if (i < 0)
+          return i;
+        else if (i && lexer->position > end) 
+          /* successful match which is longer than the current best matched */
+          end = lexer->position;
+        
+        /* advance to the next pattern */
+        pattern += pattern[0];
       }
-    }
-    Py_DECREF(groupdict);
 
-    if (action[0]) {
-      lexer->state = action[1] ? action[1] : lexer->state;
+      /* advance pattern past NULL */
+      pattern++;
 
-      if (self->verbose && action[1]) {
-        PySys_WriteStderr("switching to start condition %d, ", action[1]);
+      /* advance to the best matching position if there was a match */
+      if (end) {
+        lexer->position = ptr = end;
+        break;
       }
 
-      if (action[0] == 1) {
-        /* Just a state change, reprocess the text */
-        lexer->last = lexer->position;
-      } else {
-        yychar = action[2] ? action[2] : (int)*PyUnicode_AS_UNICODE(*yylval);
-        if (self->verbose) {
-          char *repr = unicode_escape_slice(*yylval, 0,
-                                            PyUnicode_GET_SIZE(*yylval));
-          PySys_WriteStderr("accepting '%s' (%d)\n", repr, yychar);
-          PyMem_Del(repr);
+      return 0;
+
+    case LEXER_OP_REPEAT:
+      /* repetition */
+      /* <REPEAT> <skip> <1=min> item */
+      {
+        Py_UCS4 *item = pattern + 2;
+        Py_UCS4 *next = pattern + pattern[0];
+        int minimum = pattern[1];
+        int backtracks;
+
+        lexer->position = ptr;
+        for (count = 0, i = 1; i == 1 && count < minimum; count++) {
+          REGEX_TRACE("OP_REPEAT<stage 1>, min %d, now %d\n",
+                      minimum, count);
+          i = lexer_match(self, lexer, item);
         }
-        break;
+        
+        /* either internal error or failed minimum matches */
+        if (i <= 0) 
+          return i;
+
+        backtracks = lexer->backtracks;
+
+        /* match as many items as possible */
+        for (; i == 1; count++) {
+          REGEX_TRACE("OP_REPEAT<stage 2>, now %d\n", count);
+          if (lexer_save_position(lexer) < 0)
+            return -1;
+          i = lexer_match(self, lexer, item);
+        }
+          
+        if (i < 0) {
+          /* internal error */
+          lexer->backtracks = backtracks;
+          return i;
+        }
+          
+        /* backtracking assert of tail match until success */
+        do {
+          REGEX_TRACE("OP_REPEAT<stage 3>, now %d\n", count);
+          /* update position to previous successful match */
+          ptr = lexer_restore_position(lexer);
+          if (ptr == NULL)
+            return -1;
+          i = lexer_match(self, lexer, next);
+        } while (i == 0 && --count > minimum);
+
+        /* discard remaining backtrack positions */
+        lexer->backtracks = backtracks;
+
+        if (i <= 0) {
+          return i;
+        }
+        pattern = next;
+      }
+      break;
+
+    case LEXER_OP_REPEAT_RANGE:
+      /* repetition */
+      /* <REPEAT_RANGE> <skip> <1=min> <2=max> item */
+      {
+        Py_UCS4 *item = pattern + 3;
+        Py_UCS4 *next = pattern + pattern[0];
+        int minimum = pattern[1];
+        int maximum = pattern[2];
+        int backtracks;
+
+        lexer->position = ptr;
+        for (count = 0, i = 1; i == 1 && count < minimum; count++) {
+          REGEX_TRACE("OP_REPEAT_RANGE<stage 1>, min %d, now %d\n",
+                      minimum, count);
+          i = lexer_match(self, lexer, item);
+        }
+        
+        /* either internal error or failed minimum matches */
+        if (i <= 0) 
+          return i;
+
+        backtracks = lexer->backtracks;
+
+        /* consume up to 'maximum' matches */
+        for (; i == 1 && count < maximum; count++) {
+          REGEX_TRACE("OP_REPEAT_RANGE<stage 2>, max %d, now %d\n",
+                      maximum, count);
+          if (lexer_save_position(lexer) < 0)
+            return -1;
+          i = lexer_match(self, lexer, item);
+        }
+
+        if (i < 0) {
+          /* internal error */
+          lexer->backtracks = backtracks;
+          return i;
+        }
+
+        /* maximum matches reached, update saved position */
+        if (i == 1)
+          ptr = lexer->position;
+
+        /* backtracking assert of tail match until success */
+        do {
+          REGEX_TRACE("OP_REPEAT_RANGE<stage 3>, now %d\n", count);
+          if (i == 0) {
+            /* update position to last successful match */
+            ptr = lexer_restore_position(lexer);
+            if (ptr == NULL)
+              return -1;
+          }
+          i = lexer_match(self, lexer, next);
+        } while (i == 0 && --count > minimum);
+
+        /* discard remaining backtrack positions */
+        lexer->backtracks = backtracks;
+
+        if (i <= 0)
+          return i;
+
+        pattern = next;
       }
+      break;
+
+    default:
+      REGEX_TRACE("**INTERNAL MATCH ERROR**\n");
+      return -1;
     }
-    /* simply throw away matched text */
-    Py_DECREF(*yylval);
+  }
+}
+
+static int parser_yylex(parserobject *self, lexerobject *lexer,
+			PyObject **yylval)
+{
+  int yychar = YYEMPTY;
+  int yylen;
+  Py_UNICODE *yytext = lexer->position;
+  
+  while (yytext < lexer->end && yychar == YYEMPTY) {
+    Py_UNICODE *best_end = NULL;
+    int yyaccept = 0;
+    int i;
+    Py_UCS4 **patterns = (Py_UCS4 **)lexer_patterns[lexer->state];
+    const int *actions = lexer_actions[lexer->state];
+
+    REGEX_TRACE("Using patterns from lexer state %d\n", lexer->state);
+    for (i = 0; patterns[i]; i++) {
+      int matched;
+      /* reset position each time through */
+      lexer->position = yytext;
+
+      REGEX_TRACE("--- pattern %d...\n", i);
+      matched = lexer_match(self, lexer, patterns[i]);
+      
+      if (matched > 0 && lexer->position > best_end) {
+        /* successful match which is longer than the current best matched */
+        best_end = lexer->position;
+        yyaccept = i;
+      } else if (matched < 0) {
+        /* internal error */
+	REGEX_TRACE("--- pattern %d internal error\n", i);
+        PyErr_SetString(PyExc_RuntimeError,
+                        "internal error in regular expression engine");
+        return -1;
+      }
+      REGEX_TRACE("--- pattern %d %s\n", i, matched ? "success" : "failed");
+    }
+      
+    if (best_end == NULL) {
+      /* no matches */
+      lexer->position = yytext;
+      lexer_error(lexer);
+      return -1;
+    }
+
+    lexer->position = best_end;
+    yylen = best_end - yytext;
+
+    /* get the action block for this match */
+    switch (actions[yyaccept]) {
+case 0: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 8 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[8], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = OR;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 1: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 13 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[13], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = AND;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 2: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 18 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[18], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = MULTIPLY_OPERATOR;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 3: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 24 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[24], ");
+  /* skip over the matched text */
+  yytext = lexer->position;
+  break;
+}
+case 4: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 26 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[26], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  break;
+}
+case 5: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 31 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[31], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = (int)*yytext;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 6: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 36 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[36], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = DOUBLE_COLON;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 7: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 41 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[41], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = DOUBLE_SLASH;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 8: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 46 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[46], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = EQUALITY_OP;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 9: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 51 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[51], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
   }
 
-  if (lexer->last >= lexer->end && yychar == YYEMPTY) {
+  yychar = RELATIONAL_OP;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 10: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 57 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[57], ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = NODE_TYPE;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 11: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 62 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[62], ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = AXIS_NAME;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 12: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 67 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[67], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = LITERAL;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 13: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 72 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[72], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = NLITERAL;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 14: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 77 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[77], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = VARIABLE_REFERENCE;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 15: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 82 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[82], ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = FUNCTION_NAME;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 16: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 86 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[86], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = WILDCARD_NAME;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 17: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 91 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[91], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = DOUBLE_DOT;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 18: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 97 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[97], ");
+  lexer->state = LEXER_OPERATOR;
+  TRACE("switching to start condition OPERATOR, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = (int)*yytext;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+case 19: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 103 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[103], ");
+  /* skip over the matched text */
+  yytext = lexer->position;
+  break;
+}
+case 20: {
+  /* from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag, line 105 */
+  TRACE("using rule from Ft/Xml/XPath/XPathLexerPatterns.bgen.frag[105], ");
+  lexer->state = LEXER_INITIAL;
+  TRACE("switching to start condition INITIAL, ");
+  /* create the Python object for the matched text */
+  *yylval = PyUnicode_FromUnicode(yytext, yylen);
+  if (*yylval == NULL) {
+    PyErr_NoMemory();
+    return -1;
+  }
+
+  yychar = (int)*yytext;
+
+  if (self->verbose) {
+    char *repr = unicode_escape(yytext, yylen);
+    TRACE("accepting '%s' (%d)\n", repr, yychar);
+    PyMem_Del(repr);
+  }
+
+  /* update the saved position */
+  yytext = lexer->position;
+  break;
+}
+    }
+  }
+
+  if (yychar == YYEMPTY) {
     /* Reached end of input */
     yychar = YYEOF;
@@ -2760,105 +4073,171 @@
 }
 
-static PyMethodDef parser_methods[] = {
-     { "parse", (PyCFunction)parser_parse, METH_VARARGS, parser_parse__doc__ },
-     { NULL, NULL }
-};
+/** Type Object *******************************************************/
 
-static PyObject* parser_getattr(parserobject *self, char *name)
+static int parser_traverse(parserobject *self, visitproc visit, void *arg)
 {
-  if (strcmp(name, "debug") == 0)
-    return PyInt_FromLong(self->verbose);
+  int rv;
 
-  if (strcmp(name, "__members__") == 0) {
-    PyObject *members = PyList_New(1);
-    PyList_SET_ITEM(members, 0, PyString_FromString("debug"));
-    return members;
+  if (self->dict) {
+    rv = visit(self->dict, arg);
+    if (rv != 0) return rv;
   }
-  return Py_FindMethod(parser_methods, (PyObject *)self, name);
+  return 0;
 }
 
-static int parser_setattr(parserobject *self, char *name, PyObject *value)
+static int parser_clear(parserobject *self)
 {
-  /* Set attribute 'name' to value 'v'. v==NULL means delete */
-  if (strcmp(name, "debug") == 0) {
-    if (value == NULL) {
-      PyErr_Format(PyExc_TypeError, "attribute can't be deleted: %s", name);
-      return -1;
-    } else {
-      if (PyObject_IsTrue(value))
-        self->verbose = 1;
-      else
-        self->verbose = 0;
-      return 0;
+  PyObject *tmp;
+
+  if (self->dict) {
+    tmp = self->dict;
+    self->dict = NULL;
+    Py_DECREF(tmp);
+  }
+  return 0;
+}
+
+static void parser_dealloc(parserobject *self)
+{
+  parser_clear(self);
+  self->ob_type->tp_free((PyObject *) self);
+}
+
+static int parser_init(parserobject *self, PyObject *args, PyObject *kwds)
+{
+  PyObject *debug=NULL;
+  static char *kwlist[] = { "debug", NULL };
+
+  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:" PARSER_NAME, kwlist,
+                                   &debug))
+    return -1;
+
+  if (debug) {
+    self->verbose = PyObject_IsTrue(debug);
+  }
+
+  return 0;
+}
+
+static PyObject *parser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+  parserobject *self;
+
+  self = (parserobject *) type->tp_alloc(type, 0);
+  if (self != NULL) {
+    self->dict = PyDict_New();
+    if (self->dict == NULL) {
+      Py_DECREF(self);
+      return NULL;
     }
+    self->verbose = 0;
   }
-  PyErr_SetString(PyExc_AttributeError, name);
-  return -1;
+  return (PyObject *) self;
 }
 
-static PyTypeObject ParserType = {
-  PyObject_HEAD_INIT(0)
-  0,                           /*ob_size*/
-  "parser",                    /*tp_name*/
-  sizeof(parserobject),        /*tp_basicsize*/
-  0,                           /*tp_itemsize*/
-  (destructor)parser_dealloc,  /*tp_dealloc*/
-  0,                           /*tp_print*/
-  (getattrfunc)parser_getattr, /*tp_getattr*/
-  (setattrfunc)parser_setattr, /*tp_setattr*/
-  0,                           /*tp_compare*/
-  0,                           /*tp_repr*/
-  0,                           /*tp_as_number*/
-  0,                           /*tp_as_sequence*/
-  0,                           /*tp_as_mapping*/
-  0,                           /*tp_hash*/
-  0,                           /*tp_call*/
-  0,                           /*tp_str*/
-  0,                           /*tp_getattro*/
-  0,                           /*tp_setattro*/
-  0,                           /*tp_as_buffer*/
-  0,                           /*tp_flags*/
-  parserobject__doc__,         /*tp_doc*/
-  0,                           /*tp_traverse*/
-  0,                           /*tp_clear*/
+static PyMethodDef parser_methods[] = {
+  { "parse", (PyCFunction) parser_parse, METH_O, parse_doc },
+  { NULL, NULL }
+};
+
+static PyMemberDef parser_members[] = {
+  { "debug", T_INT, offsetof(parserobject, verbose) },
+  { NULL }
+};
+
+static char parser_doc[] = PARSER_NAME "\
+([debug]) -> parser\n\
+Create a new parser object.\n\
+\n\
+The optional debug argument, when true, enables the builtin trace facility.\n\
+The trace facility uses stderr to display each step taken by the parser.";
+
+static PyTypeObject Parser_Type = {
+  /* PyObject_HEAD     */ PyObject_HEAD_INIT(NULL)
+  /* ob_size           */ 0,
+  /* tp_name           */ PROJECT_NAME "." PARSER_NAME,
+  /* tp_basicsize      */ sizeof(parserobject),
+  /* tp_itemsize       */ 0,
+  /* tp_dealloc        */ (destructor) parser_dealloc,
+  /* tp_print          */ (printfunc) 0,
+  /* tp_getattr        */ (getattrfunc) 0,
+  /* tp_setattr        */ (setattrfunc) 0,
+  /* tp_compare        */ (cmpfunc) 0,
+  /* tp_repr           */ (reprfunc) 0,
+  /* tp_as_number      */ (PyNumberMethods *) 0,
+  /* tp_as_sequence    */ (PySequenceMethods *) 0,
+  /* tp_as_mapping     */ (PyMappingMethods *) 0,
+  /* tp_hash           */ (hashfunc) 0,
+  /* tp_call           */ (ternaryfunc) 0,
+  /* tp_str            */ (reprfunc) 0,
+  /* tp_getattro       */ (getattrofunc) 0,
+  /* tp_setattro       */ (setattrofunc) 0,
+  /* tp_as_buffer      */ (PyBufferProcs *) 0,
+  /* tp_flags          */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
+  /* tp_doc            */ (char *) parser_doc,
+  /* tp_traverse       */ (traverseproc) parser_traverse,
+  /* tp_clear          */ (inquiry) parser_clear,
+  /* tp_richcompare    */ (richcmpfunc) 0,
+  /* tp_weaklistoffset */ 0,
+  /* tp_iter           */ (getiterfunc) 0,
+  /* tp_iternext       */ (iternextfunc) 0,
+  /* tp_methods        */ (PyMethodDef *) parser_methods,
+  /* tp_members        */ (PyMemberDef *) parser_members,
+  /* tp_getset         */ (PyGetSetDef *) 0,
+  /* tp_base           */ (PyTypeObject *) 0,
+  /* tp_dict           */ (PyObject *) 0,
+  /* tp_descr_get      */ (descrgetfunc) 0,
+  /* tp_descr_set      */ (descrsetfunc) 0,
+  /* tp_dictoffset     */ offsetof(parserobject, dict),
+  /* tp_init           */ (initproc) parser_init,
+  /* tp_alloc          */ (allocfunc) 0,
+  /* tp_new            */ (newfunc) parser_new,
+  /* tp_free           */ 0,
 };
 
 /* Helper functions */
 
-static char *unicode_escape_slice(PyObject *unicode, int start, int end)
+/* caller is responsible for releasing the memory */
+static char *unicode_escape(Py_UNICODE *s, int len)
 {
-  static const char *hexdigit = "0123456789abcdef";
+  static const char *hexdigit = "0123456789ABCDEF";
   char *repr, *p;
-  Py_UNICODE *s;
-  int size;
-
-  /* make ass-slices front-slices (hey, Python/C terminology) */
-  if (start < 0 || end < 0) {
-    size = PyUnicode_GET_SIZE(unicode);
-    if (size < 0)
-      return NULL;
-    if (start < 0)
-      start += size;
-    if (end < 0)
-      end += size;
-  }
+  int i, size;
 
-  /* make sure we are walking forward */
-  if (start > end) {
-    int t = start;
-    start = end;
-    end = t;
+  /* Do one pass to get the repr'ed size */
+  size = 1;  /* zero terminator */
+  for (i = 0; i < len; i++) {
+#ifdef Py_UNICODE_WIDE
+    if (s[i] >= 65536) size += 10;  /* \UHHHHHHHH */
+    else
+#endif
+    if (s[i] >= 256) size += 6;  /* \uHHHH */
+    else if (s[i] == 9 || s[i] == 10 || s[i] == 13) size += 2;  /* \t \n \r */
+    else if (s[i] < 32 || s[i] >= 128) size += 4;  /* \xHH */
+    else size++; /* printable US-ASCII */
   }
-
-  size = end - start;
-  repr = PyMem_New(char, 6*size + 1);
+  
+  repr = p = PyMem_New(char, size + 1);
   if (repr == NULL) return NULL;
 
-  p = repr;
-  s = PyUnicode_AS_UNICODE(unicode) + start;
-
-  while (size-- > 0) {
+  while (len-- > 0) {
     Py_UNICODE ch = *s++;
+#ifdef Py_UNICODE_WIDE
+    /* Map 32-bit characters to '\Uxxxxxxxx' */
+    if (ch >= 65536) {
+      *p++ = '\\';
+      *p++ = 'U';
+      *p++ = hexdigit[(ch >> 28) & 0xf];
+      *p++ = hexdigit[(ch >> 24) & 0xf];
+      *p++ = hexdigit[(ch >> 20) & 0xf];
+      *p++ = hexdigit[(ch >> 16) & 0xf];
+      *p++ = hexdigit[(ch >> 12) & 0xf];
+      *p++ = hexdigit[(ch >> 8) & 0xf];
+      *p++ = hexdigit[(ch >> 4) & 0xf];
+      *p++ = hexdigit[ch & 15];
+    }
     /* Map 16-bit characters to '\uxxxx' */
+    else 
+#endif
     if (ch >= 256) {
       *p++ = '\\';
@@ -2870,18 +4249,18 @@
     }
     /* Map special whitespace to '\t', \n', '\r' */
-    else if (ch == '\t') {
+    else if (ch == 9) {
       *p++ = '\\';
       *p++ = 't';
     }
-    else if (ch == '\n') {
+    else if (ch == 10) {
       *p++ = '\\';
       *p++ = 'n';
     }
-    else if (ch == '\r') {
+    else if (ch == 13) {
       *p++ = '\\';
       *p++ = 'r';
     }
     /* Map non-printable US ASCII to '\xhh' */
-    else if (ch < ' ' || ch >= 128) {
+    else if (ch < 32 || ch >= 128) {
       *p++ = '\\';
       *p++ = 'x';
@@ -2900,7 +4279,5 @@
 
 static void calculate_position(lexerobject *lexer, int *line, int *column) {
-  /* Update line and column numbers */
-  Py_UNICODE *start = PyUnicode_AS_UNICODE(lexer->text);
-  Py_UNICODE *end = start + lexer->position;
+  /* Determine line and column numbers */
   Py_UNICODE *p;
 
@@ -2908,5 +4285,5 @@
   *column = 1;
 
-  for (p = start; p < end; p++) {
+  for (p = PyUnicode_AS_UNICODE(lexer->text); p < lexer->end; p++) {
     if ((char)*p == '\n') {
       *line += 1;
@@ -2927,5 +4304,6 @@
 
   if (lval) {
-    matched = unicode_escape_slice(lval, 0, PyUnicode_GET_SIZE(lval));
+    matched = unicode_escape(PyUnicode_AS_UNICODE(lval), 
+                             PyUnicode_GET_SIZE(lval));
     if (matched == NULL) return NULL;
   }
@@ -2996,5 +4374,5 @@
 {
   int line, column;
-  char *repr = unicode_escape_slice(lexer->text, lexer->position, lexer->end);
+  char *repr = unicode_escape(lexer->position, (lexer->end - lexer->position));
   if (repr == NULL) return;
 
@@ -3034,97 +4412,453 @@
 }
 
-static char module_new_parser__doc__[] = "\
-CreateParser([debug]) -> parser\n\
-Create a new parser object.\n\
-\n\
-The optional debug argument, when true, enables the builtin trace facility.\n\
-The trace facility uses stderr to display each step taken by the parser.";
+/** Interactive parser ************************************************/
+
+#define CONSOLE_NAME PARSER_NAME "Console"
 
-static PyObject *module_new_parser(PyObject *self, PyObject *args)
+typedef struct {
+  PyObject_HEAD
+  parserobject *parser;
+  PyObject *dict;
+} consoleobject;
+
+static PyObject *console_new(PyTypeObject *type, PyObject *args,
+			     PyObject *kwds)
 {
-  int debug = 0;
+  consoleobject *self;
 
-  if (!PyArg_ParseTuple(args, "|i:new", &debug)) return NULL;
+  self = (consoleobject *) type->tp_alloc(type, 0);
+  if (self != NULL) {
+    PyObject *args = Py_BuildValue("(i)", 1);
+    if (args == NULL) {
+      Py_DECREF(self);
+      return NULL;
+    }
+    self->parser = (parserobject *) parser_new(&Parser_Type, args, NULL);
+    Py_DECREF(args);
+    if (self->parser == NULL) {
+      Py_DECREF(self);
+      return NULL;
+    }
+  }
+  return (PyObject *) self;
+}
 
-  return newparserobject(debug ? 1 : 0);
+static int console_init(consoleobject *self, PyObject *args, PyObject *kwds)
+{
+  PyObject *bases, *base, *result;
+  int size, i;
+
+  if (!PyArg_ParseTuple(args, ":" CONSOLE_NAME)) return -1;
+
+  bases = self->ob_type->tp_bases;
+  size = PyTuple_GET_SIZE(bases);
+  for (i = 0; i < size; i++) {
+    base = PyTuple_GET_ITEM(bases, i);
+    result = PyObject_CallMethod(base, "__init__", "O", (PyObject *) self);
+    if (result == NULL) return -1;
+    Py_DECREF(result);
+  }
+  return 0;
+}
+
+static void console_dealloc(consoleobject *self)
+{
+  Py_XDECREF(self->parser);
+  self->ob_type->tp_free((PyObject *) self);
+}
+
+static PyObject *console_cmdloop(consoleobject *self, PyObject *args)
+{
+  PyObject *result=NULL, *builtins=NULL, *readline=NULL, *old_completer=NULL;
+  int stop;
+
+  builtins = PyImport_ImportModule("__builtin__");
+  if (builtins == NULL) goto exit;
+
+  readline = PyImport_ImportModule("readline");
+  if (readline == NULL) {
+    if (!PyErr_ExceptionMatches(PyExc_ImportError)) goto exit;
+    PyErr_Clear();
+  } else {
+#if PY_VERSION_HEX > 0x02030000
+    /* old_completer = readline.get_completer() */
+    old_completer = PyObject_CallMethod(readline, "get_completer", NULL);
+    if (old_completer == NULL) goto exit;
+#endif
+    /* readline.set_completer(self.complete) */
+    result = PyObject_GetAttrString((PyObject *) self, "complete");
+    if (result == NULL) goto exit;
+    result = PyObject_CallMethod(readline, "set_completer", "N", result);
+    if (result == NULL) goto exit;
+    Py_DECREF(result);
+    /* readline.parse_and_bind("tab: complete") */
+    result = PyObject_CallMethod(readline, "parse_and_bind", "s",
+				 "tab: complete");
+    if (result == NULL) goto exit;
+    Py_DECREF(result);
+  }
+
+  stop = 0;
+  do {
+    result = PyObject_GetAttrString((PyObject *) self, "prompt");
+    if (result == NULL) goto finally;
+    result = PyObject_CallMethod(builtins, "raw_input", "N", result);
+    if (result == NULL) {
+      if (PyErr_ExceptionMatches(PyExc_EOFError) ||
+	  PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
+	PyErr_Clear();
+	PySys_WriteStdout("\n");
+	Py_INCREF(Py_None);
+	result = Py_None;
+      }
+      goto finally;
+    }
+    result = PyObject_CallMethod((PyObject *) self, "onecmd", "N", result);
+    if (result == NULL) goto finally;
+    stop = PyObject_IsTrue(result);
+    Py_DECREF(result);
+  } while (!stop);
+
+  Py_INCREF(Py_None);
+  result = Py_None;
+
+ finally:
+#if PY_VERSION_HEX > 0x02030000
+  if (readline != NULL && old_completer != NULL) {
+    PyObject *rv;
+    rv = PyObject_CallMethod(readline, "set_completer", "O", old_completer);
+    if (rv == NULL) {
+      Py_XDECREF(result);
+      result = rv;
+    } else {
+      Py_DECREF(rv);
+    }
+  }
+#endif
+ exit:
+  Py_XDECREF(old_completer);
+  Py_XDECREF(readline);
+  Py_XDECREF(builtins);
+  return result;
+}
+
+static PyObject *console_emptyline(consoleobject *self, PyObject *noarg)
+{
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static char console_exit_doc[] = "terminate the console";
+
+static PyObject *console_exit(consoleobject *self, PyObject *arg)
+{
+  Py_INCREF(Py_True);
+  return Py_True;
+}
+
+static char console_debug_doc[] = "sets or displays the debug level";
+
+static PyObject *console_debug(consoleobject *self, PyObject *arg)
+{
+  PyObject *verbose;
+
+  if (PyObject_IsTrue(arg)) {
+    if ((verbose = PyNumber_Int(arg)) == NULL) {
+      if (PyErr_ExceptionMatches(PyExc_ValueError)) {
+	PyErr_Clear();
+	PySys_WriteStdout("usage: debug <level>\n");
+	Py_INCREF(Py_None);
+	return Py_None;
+      }
+      return NULL;
+    }
+    self->parser->verbose = PyInt_AsLong(verbose);
+    Py_DECREF(verbose);
+  }
+  PySys_WriteStdout("debug level is %d\n", self->parser->verbose);
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static char console_parse_doc[] = "parses an expression";
+
+static PyObject *console_parse(consoleobject *self, PyObject *arg)
+{
+  PyObject *result, *value;
+
+  result = parser_parse(self->parser, arg);
+  if (result == NULL) {
+    PyObject *exc, *tb;
+    if (!PyErr_ExceptionMatches(PyExc_SyntaxError)) return NULL;
+    PyErr_Fetch(&exc, &value, &tb);
+    if (value && value != Py_None) {
+      result = PyObject_Str(value);
+    }
+    Py_XDECREF(exc);
+    Py_XDECREF(value);
+    Py_XDECREF(tb);
+    if (result == NULL) return NULL;
+  }
+
+  value = PyObject_Str(result);
+  Py_DECREF(result);
+  if (value == NULL) return NULL;
+
+  PySys_WriteStdout("%s\n", PyString_AsString(value));
+  Py_DECREF(value);
+
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+static PyMethodDef console_methods[] = {
+  { "cmdloop", (PyCFunction) console_cmdloop, METH_O },
+  { "emptyline", (PyCFunction) console_emptyline, METH_NOARGS },
+  { "do_exit", (PyCFunction) console_exit, METH_O, console_exit_doc },
+  { "do_quit", (PyCFunction) console_exit, METH_O, console_exit_doc },
+  { "do_debug", (PyCFunction) console_debug, METH_O, console_debug_doc },
+  { "do_parse", (PyCFunction) console_parse, METH_O, console_parse_doc },
+  { NULL }
+};
+
+static PyTypeObject Console_Type = {
+  /* PyObject_HEAD     */ PyObject_HEAD_INIT(NULL)
+  /* ob_size           */ 0,
+  /* tp_name           */ "Console",
+  /* tp_basicsize      */ sizeof(consoleobject),
+  /* tp_itemsize       */ 0,
+  /* tp_dealloc        */ (destructor) console_dealloc,
+  /* tp_print          */ (printfunc) 0,
+  /* tp_getattr        */ (getattrfunc) 0,
+  /* tp_setattr        */ (setattrfunc) 0,
+  /* tp_compare        */ (cmpfunc) 0,
+  /* tp_repr           */ (reprfunc) 0,
+  /* tp_as_number      */ (PyNumberMethods *) 0,
+  /* tp_as_sequence    */ (PySequenceMethods *) 0,
+  /* tp_as_mapping     */ (PyMappingMethods *) 0,
+  /* tp_hash           */ (hashfunc) 0,
+  /* tp_call           */ (ternaryfunc) 0,
+  /* tp_str            */ (reprfunc) 0,
+  /* tp_getattro       */ (getattrofunc) 0,
+  /* tp_setattro       */ (setattrofunc) 0,
+  /* tp_as_buffer      */ (PyBufferProcs *) 0,
+  /* tp_flags          */ Py_TPFLAGS_DEFAULT,
+  /* tp_doc            */ (char *) 0,
+  /* tp_traverse       */ (traverseproc) 0,
+  /* tp_clear          */ (inquiry) 0,
+  /* tp_richcompare    */ (richcmpfunc) 0,
+  /* tp_weaklistoffset */ 0,
+  /* tp_iter           */ (getiterfunc) 0,
+  /* tp_iternext       */ (iternextfunc) 0,
+  /* tp_methods        */ (PyMethodDef *) console_methods,
+  /* tp_members        */ (PyMemberDef *) 0,
+  /* tp_getset         */ (PyGetSetDef *) 0,
+  /* tp_base           */ (PyTypeObject *) 0,
+  /* tp_dict           */ (PyObject *) 0,
+  /* tp_descr_get      */ (descrgetfunc) 0,
+  /* tp_descr_set      */ (descrsetfunc) 0,
+  /* tp_dictoffset     */ offsetof(consoleobject, dict),
+  /* tp_init           */ (initproc) console_init,
+  /* tp_alloc          */ (allocfunc) 0,
+  /* tp_new            */ (newfunc) console_new,
+  /* tp_free           */ 0,
+};
+
+static char console_doc[] = CONSOLE_NAME "\
+()\n\
+Starts an interactive parser console.";
+
+static PyObject *module_console(PyObject *module, PyObject *args)
+{
+  PyObject *console, *result;
+
+  args = PyTuple_New(0);
+  if (args == NULL) return NULL;
+
+  console = PyObject_Call((PyObject *) &Console_Type, args, NULL);
+  if (console == NULL) {
+    Py_DECREF(args);
+    return NULL;
+  }
+  result = console_cmdloop((consoleobject *) console, args);
+  Py_DECREF(args);
+  Py_DECREF(console);
+  return result;
 }
 
 static PyMethodDef module_methods[] = {
-  {"new", module_new_parser, METH_VARARGS, module_new_parser__doc__},
-  {NULL, NULL}
+  { CONSOLE_NAME, module_console, METH_NOARGS, console_doc },
+  { NULL }
 };
-DL_EXPORT(void) initXPathParserc(void) {
-  PyObject *m, *dict;
-  PyObject *modules;
-  PyObject *re, *multiline;
-
-  m = Py_InitModule("XPathParserc", module_methods);
-  modules = PyImport_GetModuleDict();
-  ParserType.ob_type = &PyType_Type;
-
-  re = PyDict_GetItemString(modules, "re");
-  if (!re) {
-    re = PyImport_ImportModule("re");
-  }
-  dict = PyModule_GetDict(re);
-  multiline = PyDict_GetItemString(dict, "MULTILINE");
-  patterns[1] = PyObject_CallMethod(re, "compile", "sO",
-                                     "(?P<p5>\\)|\\])|(?P<p6>::)|(?P<p7>//)|(?P<p8>=|!=)|(?P<p9><=|<|>=|>)|(?P<p10>(node|text|comment|processing-instruction)(?=[\\t\\n\\r\\s]*\\())|(?P<p11>[a-zA-Z_][a-zA-Z0-9_.-]*(?=[\\t\\n\\r\\s]*::))|(?P<p12>('[^']*')|(\"[^\"]*\"))|(?P<p13>([0-9]+(\\.([0-9]+)?)?)|(\\.[0-9]+))|(?P<p14>\\$([a-zA-Z_][a-zA-Z0-9_.-]*:)?[a-zA-Z_][a-zA-Z0-9_.-]*)|(?P<p15>([a-zA-Z_][a-zA-Z0-9_.-]*:)?[a-zA-Z_][a-zA-Z0-9_.-]*(?=[\\t\\n\\r\\s]*\\())|(?P<p16>([a-zA-Z_][a-zA-Z0-9_.-]*:\\*)|(([a-zA-Z_][a-zA-Z0-9_.-]*:)?[a-zA-Z_][a-zA-Z0-9_.-]*)|\\*)|(?P<p17>\\.\\.)|(?P<p18>\\.)|(?P<p19>[\\t\\n\\r\\s]+)|(?P<p20>.)", multiline);
-  patterns[2] = PyObject_CallMethod(re, "compile", "sO",
-                                     "(?P<p0>or)|(?P<p1>and)|(?P<p2>\\*|mod|div)|(?P<p3>[\\t\\n\\r\\s])|(?P<p4>.)", multiline);
-
-  ParsedAbsoluteLocationPath = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedAbsoluteLocationPath");
-  if (!ParsedAbsoluteLocationPath) {
-    ParsedAbsoluteLocationPath = PyImport_ImportModule("Ft.Xml.XPath.ParsedAbsoluteLocationPath");
-    if (!ParsedAbsoluteLocationPath) return;
-    Py_XDECREF(ParsedAbsoluteLocationPath);
-  }
-  ParsedRelativeLocationPath = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedRelativeLocationPath");
-  if (!ParsedRelativeLocationPath) {
-    ParsedRelativeLocationPath = PyImport_ImportModule("Ft.Xml.XPath.ParsedRelativeLocationPath");
-    if (!ParsedRelativeLocationPath) return;
-    Py_XDECREF(ParsedRelativeLocationPath);
-  }
-  ParsedPredicateList = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedPredicateList");
-  if (!ParsedPredicateList) {
-    ParsedPredicateList = PyImport_ImportModule("Ft.Xml.XPath.ParsedPredicateList");
-    if (!ParsedPredicateList) return;
-    Py_XDECREF(ParsedPredicateList);
-  }
-  ParsedStep = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedStep");
-  if (!ParsedStep) {
-    ParsedStep = PyImport_ImportModule("Ft.Xml.XPath.ParsedStep");
-    if (!ParsedStep) return;
-    Py_XDECREF(ParsedStep);
-  }
-  ParsedAxisSpecifier = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedAxisSpecifier");
-  if (!ParsedAxisSpecifier) {
-    ParsedAxisSpecifier = PyImport_ImportModule("Ft.Xml.XPath.ParsedAxisSpecifier");
-    if (!ParsedAxisSpecifier) return;
-    Py_XDECREF(ParsedAxisSpecifier);
-  }
-  ParsedNodeTest = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedNodeTest");
-  if (!ParsedNodeTest) {
-    ParsedNodeTest = PyImport_ImportModule("Ft.Xml.XPath.ParsedNodeTest");
-    if (!ParsedNodeTest) return;
-    Py_XDECREF(ParsedNodeTest);
-  }
-  ParsedAbbreviatedAbsoluteLocationPath = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedAbbreviatedAbsoluteLocationPath");
-  if (!ParsedAbbreviatedAbsoluteLocationPath) {
-    ParsedAbbreviatedAbsoluteLocationPath = PyImport_ImportModule("Ft.Xml.XPath.ParsedAbbreviatedAbsoluteLocationPath");
-    if (!ParsedAbbreviatedAbsoluteLocationPath) return;
-    Py_XDECREF(ParsedAbbreviatedAbsoluteLocationPath);
-  }
-  ParsedAbbreviatedRelativeLocationPath = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedAbbreviatedRelativeLocationPath");
-  if (!ParsedAbbreviatedRelativeLocationPath) {
-    ParsedAbbreviatedRelativeLocationPath = PyImport_ImportModule("Ft.Xml.XPath.ParsedAbbreviatedRelativeLocationPath");
-    if (!ParsedAbbreviatedRelativeLocationPath) return;
-    Py_XDECREF(ParsedAbbreviatedRelativeLocationPath);
-  }
-  ParsedExpr = PyDict_GetItemString(modules, "Ft.Xml.XPath.ParsedExpr");
-  if (!ParsedExpr) {
-    ParsedExpr = PyImport_ImportModule("Ft.Xml.XPath.ParsedExpr");
-    if (!ParsedExpr) return;
-    Py_XDECREF(ParsedExpr);
-  }
+
+static void import_modules(void);
+
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC DL_EXPORT(void)
+#endif
+
+PyMODINIT_FUNC MODULE_INITFUNC(void) {
+  PyObject *import, *class, *item, *module;
+  
+  if (PyType_Ready(&Parser_Type) < 0) return;
+
+  /* Setup the console type's base classes */
+  import = PyImport_ImportModule("cmd");
+  if (import == NULL) return;
+  class = PyObject_GetAttrString(import, "Cmd");
+  Py_DECREF(import);
+  if (class == NULL) return;
+  Console_Type.tp_base = &PyBaseObject_Type;
+  Console_Type.tp_bases = Py_BuildValue("(ON)", class, &PyBaseObject_Type);
+  if (Console_Type.tp_bases == NULL) return;
+  if (PyType_Ready(&Console_Type) < 0) return;
+
+  item = PyString_FromString(PARSER_NAME "> ");
+  if (PyDict_SetItemString(Console_Type.tp_dict, "prompt", item) < 0) return;
+  Py_DECREF(item);
+
+  module = Py_InitModule(PARSER_NAME "c", module_methods);
+  if (module == NULL) return;
+  
+  Py_INCREF(&Parser_Type);
+  PyModule_AddObject(module, "new", (PyObject *) &Parser_Type);
+  Py_INCREF(&Parser_Type);
+  PyModule_AddObject(module, PARSER_NAME, (PyObject *) &Parser_Type);
+
+  /* import the modules required for action routines */
+  import_modules();
+}
+
+static PyObject *import_from(char *modulename, char *fromname) {
+  PyObject *fromlist, *name, *module;
+
+  fromlist = PyTuple_New(1);
+  if (fromlist == NULL) return NULL;
+
+  name = PyString_FromString(fromname);
+  if (name == NULL) {
+    Py_DECREF(fromlist);
+    return NULL;
+  }
+  Py_INCREF(name);
+  PyTuple_SET_ITEM(fromlist, 0, name);
+
+  module = PyImport_ImportModuleEx(modulename, NULL, NULL, fromlist);
+  Py_DECREF(fromlist);
+  if (module == NULL) {
+    Py_DECREF(name);
+    return NULL;
+  }
+
+  fromlist = PyObject_GetAttr(module, name);
+  Py_DECREF(module);
+  Py_DECREF(name);
+  return fromlist;
+}
+
+static void import_modules(void) {
+  /* from Ft.Xml.XPath.ParsedAbsoluteLocationPath import ParsedAbsoluteLocationPath */
+  ParsedAbsoluteLocationPath = import_from("Ft.Xml.XPath.ParsedAbsoluteLocationPath", "ParsedAbsoluteLocationPath");
+  if (ParsedAbsoluteLocationPath == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedRelativeLocationPath import ParsedRelativeLocationPath */
+  ParsedRelativeLocationPath = import_from("Ft.Xml.XPath.ParsedRelativeLocationPath", "ParsedRelativeLocationPath");
+  if (ParsedRelativeLocationPath == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedPredicateList import ParsedPredicateList */
+  ParsedPredicateList = import_from("Ft.Xml.XPath.ParsedPredicateList", "ParsedPredicateList");
+  if (ParsedPredicateList == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedStep import ParsedStep */
+  ParsedStep = import_from("Ft.Xml.XPath.ParsedStep", "ParsedStep");
+  if (ParsedStep == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedStep import ParsedAbbreviatedStep */
+  ParsedAbbreviatedStep = import_from("Ft.Xml.XPath.ParsedStep", "ParsedAbbreviatedStep");
+  if (ParsedAbbreviatedStep == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedAxisSpecifier import ParsedAxisSpecifier */
+  ParsedAxisSpecifier = import_from("Ft.Xml.XPath.ParsedAxisSpecifier", "ParsedAxisSpecifier");
+  if (ParsedAxisSpecifier == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedNodeTest import ParsedNodeTest */
+  ParsedNodeTest = import_from("Ft.Xml.XPath.ParsedNodeTest", "ParsedNodeTest");
+  if (ParsedNodeTest == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedNodeTest import ParsedNameTest */
+  ParsedNameTest = import_from("Ft.Xml.XPath.ParsedNodeTest", "ParsedNameTest");
+  if (ParsedNameTest == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedNodeTest import PrincipalTypeTest */
+  PrincipalTypeTest = import_from("Ft.Xml.XPath.ParsedNodeTest", "PrincipalTypeTest");
+  if (PrincipalTypeTest == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedNodeTest import LocalNameTest */
+  LocalNameTest = import_from("Ft.Xml.XPath.ParsedNodeTest", "LocalNameTest");
+  if (LocalNameTest == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedAbbreviatedAbsoluteLocationPath import ParsedAbbreviatedAbsoluteLocationPath */
+  ParsedAbbreviatedAbsoluteLocationPath = import_from("Ft.Xml.XPath.ParsedAbbreviatedAbsoluteLocationPath", "ParsedAbbreviatedAbsoluteLocationPath");
+  if (ParsedAbbreviatedAbsoluteLocationPath == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedAbbreviatedRelativeLocationPath import ParsedAbbreviatedRelativeLocationPath */
+  ParsedAbbreviatedRelativeLocationPath = import_from("Ft.Xml.XPath.ParsedAbbreviatedRelativeLocationPath", "ParsedAbbreviatedRelativeLocationPath");
+  if (ParsedAbbreviatedRelativeLocationPath == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedVariableReferenceExpr */
+  ParsedVariableReferenceExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedVariableReferenceExpr");
+  if (ParsedVariableReferenceExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedLiteralExpr */
+  ParsedLiteralExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedLiteralExpr");
+  if (ParsedLiteralExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedNLiteralExpr */
+  ParsedNLiteralExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedNLiteralExpr");
+  if (ParsedNLiteralExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedFunctionCallExpr */
+  ParsedFunctionCallExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedFunctionCallExpr");
+  if (ParsedFunctionCallExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedUnionExpr */
+  ParsedUnionExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedUnionExpr");
+  if (ParsedUnionExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedPathExpr */
+  ParsedPathExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedPathExpr");
+  if (ParsedPathExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedFilterExpr */
+  ParsedFilterExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedFilterExpr");
+  if (ParsedFilterExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedOrExpr */
+  ParsedOrExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedOrExpr");
+  if (ParsedOrExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedAndExpr */
+  ParsedAndExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedAndExpr");
+  if (ParsedAndExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedEqualityExpr */
+  ParsedEqualityExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedEqualityExpr");
+  if (ParsedEqualityExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedRelationalExpr */
+  ParsedRelationalExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedRelationalExpr");
+  if (ParsedRelationalExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedAdditiveExpr */
+  ParsedAdditiveExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedAdditiveExpr");
+  if (ParsedAdditiveExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedMultiplicativeExpr */
+  ParsedMultiplicativeExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedMultiplicativeExpr");
+  if (ParsedMultiplicativeExpr == NULL) return;
+
+  /* from Ft.Xml.XPath.ParsedExpr import ParsedUnaryExpr */
+  ParsedUnaryExpr = import_from("Ft.Xml.XPath.ParsedExpr", "ParsedUnaryExpr");
+  if (ParsedUnaryExpr == NULL) return;
+
 }
--- XPathParser.py DELETED ---
New file: XPathTypes.py
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/XPathTypes.py?rev=1.1.6.1&content-type=text/vnd.viewcvs-markup

cvs checkout: cannot find module `XPathTypes.py' - ignored
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/_4xpath.py.diff?r1=1.1&r2=1.1.8.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/_4xpath.py?rev=1.1.8.1&content-type=text/vnd.viewcvs-markup

Index: _4xpath.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/_4xpath.py,v
retrieving revision 1.1
retrieving revision 1.1.8.1
diff -U2 -r1.1 -r1.1.8.1
--- _4xpath.py	16 Jul 2002 23:37:23 -0000	1.1
+++ _4xpath.py	4 Dec 2006 07:06:59 -0000	1.1.8.1
@@ -1,41 +1,77 @@
-#!/usr/bin/env python
 ########################################################################
-#
-# File Name:            _4xpath.py
-#
-# Documentation:        http://docs.4suite.org/4XPath/4xpath.py.html
-#
+# $Header$
 """
-Command-line invocation of the 4XPath
-WWW: http://4suite.org/4XPath        e-mail: support at 4suite.org
+Implementation of '4xpath' command
+(functions defined here are used by the Ft.Lib.CommandLine framework)
 
-Copyright 1999-2002 Fourthought, Inc., USA.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2006 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-import re, os, sys, traceback, types
+import re, os, sys, traceback
+
+from Ft.Lib import CloseStream
+from Ft.Lib.CommandLine import CommandLineApp, Options, Arguments
+from Ft.Lib.CommandLine.CommandLineUtil import SourceArgToInputSource
 from Ft.Xml import XPath, InputSource
-from Ft.Xml import __version__
-from Ft.Xml.XPath.Util import ExpandQName
 from Ft.Xml.XPath import Conversions
-from Ft.Lib import boolean, Uri
-
-__doc__ = """4XPath command-line application"""
+from Ft.Xml.XPath import XPathTypes as Types
+from Ft.Xml.XPath.Util import ExpandQName
 
 g_paramBindingPattern = re.compile(r"([\d\D_\.\-]*:?[\d\D_\.\-]+)=(.*)")
 g_nssBindingPattern = re.compile(r"([\d\D_\.\-]*:?[\d\D_\.\-]+)=(.*)")
 
-MAX_PYTHON_RECURSION_DEPTH=10000
+from Ft import MAX_PYTHON_RECURSION_DEPTH
 sys.setrecursionlimit(MAX_PYTHON_RECURSION_DEPTH)
 
-def Run(options,args):
 
-    if options.has_key('version'):
-        print '4XPath, from 4Suite %s' % __version__
-        return
+class XPathCommandLineApp(CommandLineApp.CommandLineApp):
 
-    if not args.has_key('source-uri'):
-        print 'A source URI argument is required. See "4xpath -h" for usage info.'
-        return
+    from Ft.__config__ import \
+        NAME as project_name, VERSION as project_version, URL as project_url
+
+    name = '4xpath'
+    summary = 'command-line tool for performing XPath queries on XML documents'
+    description = """4XPath command-line application"""
+
+    options = [
+        Options.Option(
+            'D', 'define=NAME=VALUE',
+            'Bind a top-level parameter'),
+        Options.Option(
+            'N', 'namespace=PREFIX=NAMESPACE',
+            'Define a namespace/prefix binding'),
+        Options.Option(
+            'e', 'stacktrace-on-error',
+            'Display a stack trace when an error occurs'),
+        Options.Option(
+            None, 'string',
+            'Print the string-value of the results'),
+        ]
+
+    arguments = [
+        Arguments.RequiredArgument(
+            'source-uri',
+            'The URI of the XML document to parse, or "-" to indicate'
+            ' standard input. The document\'s root node will be used as the'
+            ' context node.'),
+        Arguments.RequiredArgument(
+            'expression',
+            'The XPath expression to evaluate'),
+        ]
+
+    def validate_arguments(self, args):
+        if len(args) < 2:
+            raise SystemExit('A source URI argument and an expression'
+                             ' argument are required. See "%s -h" for usage'
+                             ' info.' % sys.argv[0])
+        return CommandLineApp.CommandLineApp.validate_arguments(self, args)
+
+    def run(self, options, arguments):
+        return Run(options, arguments)
+
+
+def Run(options,args):
 
     defs = options.get('define', [])
@@ -58,6 +94,4 @@
         top_level_params[name] = match.group(2)
 
-
-
     stringValue = options.has_key('string')
     stacktrace_on_error = options.has_key('stacktrace-on-error')
@@ -66,41 +100,33 @@
     reader = Domlette.NonvalidatingReader
 
+    sourceUri = args['source-uri']
     try:
+        source_isrc = SourceArgToInputSource(sourceUri, InputSource.DefaultFactory)
+    except Exception, e:
+        sys.stderr.write(str(e)+'\n')
+        sys.stderr.flush()
+        return
 
+    extmodules = os.environ.get("EXTMODULES")
+    if extmodules:
+        extmodules = extmodules.split(":")
+    else:
+        extmodules = []
+
+    try:
         compExpr = XPath.Compile(args['expression'])
 
-        source = args['source-uri']
-        if source == '-':
-            isrc = InputSource.InputSource(sys.stdin,'.')
-        else:
-            source = Uri.OsPathToUri(source, attemptAbsolute=1)
-            isrc = InputSource.DefaultFactory.fromUri(source)
-            
-        dom = reader.parse(isrc)
+        dom = reader.parse(source_isrc)
+        CloseStream(source_isrc, quiet=True)
 
         context = XPath.Context.Context(dom,
                                         processorNss = processorNss,
                                         varBindings = top_level_params,
-                                        extModuleList = os.environ.get("EXTMODULES","").split(":"))
-                                        
+                                        extModuleList = extmodules)
+
         res = compExpr.evaluate(context)
         if stringValue:
             res = Conversions.StringValue(res)
-        if type(res) in [types.StringType,types.UnicodeType]:
-            print "String Results: "
-            print res
-        elif type(res) in [types.IntType,types.FloatType]:
-            print "Number Results: "
-            print res
-        elif type(res) == boolean.BooleanType:
-            print "Boolean Results: "
-            print res
-        elif type(res) == types.ListType:
-            print "Node Set: "
-            for node in res:
-                print node
-        else:
-            print "Unknown Type: "
-            print res
+
     except (XPath.RuntimeException, XPath.CompiletimeException), error:
         if stacktrace_on_error:
@@ -113,61 +139,12 @@
 
 
-from Ft.Lib.CommandLine import Options, CommandLineApp, Arguments, Command
-
-
-class XPathCommandLineApp(CommandLineApp.CommandLineApp):
-    def __init__(self):
-        CommandLineApp.CommandLineApp.__init__(
-            self,
-            '4xpath',
-            '4XPath version %s' % __version__,
-            __doc__,
-            [],
-            ourOptions = Options.Options([Options.Option('V',
-                                                         'version',
-                                                         'Display program version and exit',
-                                                         ),
-                                          Options.Option('D',
-                                                         'define=NAME=VALUE',
-                                                         'Bind a top-level parameter'
-                                                         ),
-                                          Options.Option('N',
-                                                         'namespace=PREFIX=NAMESPACE',
-                                                         'Define a namespace to beused for prefix resolution'
-                                                         ),
-                                          Options.Option('e',
-                                                         'stacktrace-on-error',
-                                                         'Display a stack trace when an error occurs',
-                                                         ),
-                                          Options.Option(None,
-                                                         'string',
-                                                         'Print out the string value of the results',
-                                                         ),
-                                          #Options.Option('d',
-                                          #               'debug',
-                                          #               'Execute 4xslt in the command line debugger',
-                                          #               ),
-                                          ]),
-            enableShowCommands = 0
-            )
-
-        self.function = Run
-        self.arguments = [Arguments.OptionalArgument(
-            'source-uri',
-            'The URI of the source XML document. Required unless running "4xpath -V".'\
-            ' Note: if you use "-" as the name of the source document, the source will'\
-            ' instead be read from standard input.',
-            str),
-                          Arguments.RequiredArgument('expression',
-                                                      'The XPath expression to evaluate',
-                                                      str),
-                          ]
-
-
-    def validate_arguments(self,args):
-        return Command.Command.validate_arguments(self,args)
-
-
-
-def Register():
-    return XPathCommandLineApp()
+    if Types.g_xpathPrimitiveTypes.has_key(type(res)):
+        heading = "Result (XPath %s):" % Types.g_xpathPrimitiveTypes[type(res)]
+        if isinstance(res, Types.NodesetType):
+            res = res and '\n'.join(map(str, res)) or '<empty node-set>'
+    else:
+        heading = "Result (unknown type):"
+    sys.stderr.write('%s\n%s\n' % (heading, '=' * len(heading)))
+    sys.stderr.flush()
+    print res
+    return
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/__init__.py.diff?r1=1.18.2.1&r2=1.18.2.2
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/__init__.py?rev=1.18.2.2&content-type=text/vnd.viewcvs-markup

Index: __init__.py
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/__init__.py,v
retrieving revision 1.18.2.1
retrieving revision 1.18.2.2
diff -U2 -r1.18.2.1 -r1.18.2.2
--- __init__.py	3 Apr 2003 14:58:13 -0000	1.18.2.1
+++ __init__.py	4 Dec 2006 07:06:59 -0000	1.18.2.2
@@ -1,45 +1,16 @@
 ########################################################################
-#
-# File Name:            __init__.py
-#
-# Documentation:        http://docs.4suite.org/4Path/__init__.py.html
-#
+# $Header$
 """
-WWW: http://4suite.org/4XPath         e-mail: support at 4suite.org
+4XPath initialization and principal functions
 
-Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
-See  http://4suite.org/COPYRIGHT  for license and copyright information
+Copyright 2005 Fourthought, Inc. (USA).
+Detailed license and copyright information: http://4suite.org/COPYRIGHT
+Project home, documentation, distributions: http://4suite.org/
 """
 
-NAMESPACE_NODE = 10000
-FT_OLD_EXT_NAMESPACE = 'http://xmlns.4suite.org/xpath/extensions'
-FT_EXT_NAMESPACE = 'http://xmlns.4suite.org/ext'
-
-import sys, types
-from xml.dom import Node
-from Ft.Lib import boolean
-from Ft.Lib.number import nan as NaN
-from Ft.Lib.number import inf as Inf
+# From DOM Level 3 XPath
+XPATH_NAMESPACE_NODE = NAMESPACE_NODE = 13
 
-from Ft import FtException
-
-g_xpathPrimitiveTypes = [
-    types.StringType,
-    types.UnicodeType,
-    types.IntType,
-    types.LongType,
-    types.FloatType,
-    types.ListType,
-    boolean.BooleanType,
-    ]
-
-g_xpathRecognizedNodes = [
-        Node.ELEMENT_NODE,
-        Node.ATTRIBUTE_NODE,
-        Node.TEXT_NODE,
-        Node.DOCUMENT_NODE,
-        Node.PROCESSING_INSTRUCTION_NODE,
-        Node.COMMENT_NODE
-        ]
+FT_EXT_NAMESPACE = 'http://xmlns.4suite.org/ext'
 
 #limits are used for XPath optimization.  The default behavior is
@@ -47,90 +18,111 @@
 NOLIMIT = sys.maxint
 
+
+__all__ = [# global constants:
+           'XPATH_NAMESPACE_NODE', 'NAMESPACE_NODE', 'FT_EXT_NAMESPACE',
+           # exception classes:
+           'XPathException', 'CompiletimeException', 'RuntimeException',
+           # XPath expression parser:
+           'g_parser', 'parser',
+           # XPath context API:
+           'Context', #the module; is this necessary to expose?
+           # XPath expression processing:
+           'Compile', 'Evaluate', 'SimpleEvaluate',
+           # DOM preparation for XPath processing:
+           'NormalizeNode',
+           ]
+
+
+# -- XPath exceptions --------------------------------------------------------
+
+from Ft import FtException
+
 class XPathException(FtException):
-    def __init__(self, errorCode, messages, args):
-        FtException.__init__(self, errorCode, messages, args)
+    """
+    Base class for exceptions specific to XPath processing
+    """
+    def __init__(self, errorCode, messages, *args, **kwds):
+        FtException.__init__(self, errorCode, messages, args, **kwds)
+
 
 class CompiletimeException(XPathException):
+    """
+    The exception raised when an error is encountered during the
+    parsing or compilation of an XPath expression.
+    """
+    #errorCodes:
+    # internal/unexpected errors
     INTERNAL = 1
+    # other expression compile-time errors
     SYNTAX = 2
-    PROCESSING = 3
 
-    def __init__(self, errorCode, *args):
-        XPathException.__init__(self, errorCode, MessageSource.COMPILETIME, args)
+    def __init__(self, errorCode, *args, **kwds):
+        # import here to avoid circularity
+        import MessageSource
+        XPathException.__init__(self, errorCode,
+                                MessageSource.ERROR_COMPILETIME,
+                                *args, **kwds)
         return
 
+
 class RuntimeException(XPathException):
+    """
+    The exception raised when an error is encountered during the
+    parsing or evaluation of an XPath expression.
+    """
+    #errorCodes:
+    # internal/unexpected errors
     INTERNAL = 1
-    NO_CONTEXT = 10
+    # other expression evaluation (run-time) errors
+    NO_CONTEXT         = 10
     UNDEFINED_VARIABLE = 100
-    UNDEFINED_PREFIX = 101
+    UNDEFINED_PREFIX   = 101
     UNDEFINED_FUNCTION = 102
-
-    WRONG_ARGUMENTS = 200
-    ARGCOUNT_NONE = 201
-    ARGCOUNT_ATLEAST = 202
-    ARGCOUNT_EXACT = 203
-    ARGCOUNT_ATMOST = 204
-    
-    def __init__(self, errorCode, *args):
-        XPathException.__init__(self, errorCode, MessageSource.RUNTIME, args)
+    WRONG_ARGUMENTS    = 200
+    ARGCOUNT_NONE      = 201
+    ARGCOUNT_ATLEAST   = 202
+    ARGCOUNT_EXACT     = 203
+    ARGCOUNT_ATMOST    = 204
+
+    def __init__(self, errorCode, *args, **kwds):
+        # import here to avoid circularity
+        import MessageSource
+        XPathException.__init__(self, errorCode,
+                                MessageSource.ERROR_RUNTIME,
+                                *args, **kwds)
         return
 
 
-import MessageSource
+# -- Additional setup --------------------------------------------------------
 
-def Evaluate(expr, contextNode=None, context=None):
-    import os
-    if os.environ.has_key('EXTMODULES'):
-        ext_modules = os.environ["EXTMODULES"].split(':')
-    else:
-        ext_modules = []
-
-    if contextNode and context:
-        con = context.clone()
-        con.node = contextNode
-    elif context:
-        con = context
-    elif contextNode:
-        con = Context.Context(contextNode, 0, 0, extModuleList=ext_modules)
-    else:
-        raise RuntimeException(RuntimeException.NO_CONTEXT_ERROR)
-
-    if hasattr(expr, "evaluate"):
-        retval = expr.evaluate(con)
-    else:
-        retval = parser.new().parse(expr).evaluate(con)
-    return retval
-
-
-def Compile(expr):
-    if type(expr) not in [types.StringType, types.UnicodeType]:
-        raise TypeError("Expected string, found %s" % type(expr))
-    try:
-        return parser.new().parse(expr)
-    except SyntaxError, error:
-        raise CompiletimeException(CompiletimeException.SYNTAX, 0,0,str(error))
-    except:
-        import traceback, cStringIO
-        stream = cStringIO.StringIO()
-        traceback.print_exc(None, stream)
-        raise RuntimeException(RuntimeException.INTERNAL, stream.getvalue())
+# This occurs near the end because we want to avoid circular import
+# problems when the parser imports the expression token classes.
+import XPathParserc as XPathParser
+parser = XPathParser
+
+# 2004-09-07 - uogbuji:
+#   Name module global properly. Leave "parser" alone for now for
+#   backwards-compat. Name "parser" is deprecated.
+# 2004-10-15 - jkloth:
+#   "parser" is not really a global variable, it is a module alias.  The
+#   aliasing appears here instead of in XPathParser.py as that file takes a
+#   long time to import and allows the ability of testing both versions by
+#   importing each separately.
+#   The name was chosen as lowercase to aid in merging with the PyXML codebase.
+#   However, the XPath codebase has diverged greatly (Domlette/minidom
+#   differences) so a new name is acceptible/appropriate, keeping in mind that
+#   this name refers to a module.  I suggest simply "Parser".
+g_parser = parser
 
 
-def CreateContext(contextNode):
-    return Context.Context(contextNode, 0, 0)
+# -- Core XPath API ----------------------------------------------------------
 
+import Context
 
+from Util import Evaluate, SimpleEvaluate, Compile
 
 #Allow access to the NormalizeNode function
 from Util import NormalizeNode
 
-import Context
-
-try:
-    import XPathParserc
-    parser = XPathParserc
-except ImportError:
-    import XPathParser
-    parser = XPathParser
-
+Util.XPathParser = g_parser
+Util.Context = Context
New file: _comparisons.c
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/_comparisons.c?rev=1.1.8.1&content-type=text/vnd.viewcvs-markup

cvs checkout: cannot find module `_comparisons.c' - ignored
ViewCVS diff:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/_conversions.c.diff?r1=1.3&r2=1.3.2.1
ViewCVS view:
  http://cvs.4suite.org/viewcvs/4Suite/Ft/Xml/XPath/_conversions.c?rev=1.3.2.1&content-type=text/vnd.viewcvs-markup

Index: _conversions.c
===================================================================
RCS file: /var/local/cvsroot/4Suite/Ft/Xml/XPath/_conversions.c,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -U2 -r1.3 -r1.3.2.1
--- _conversions.c	5 Dec 2002 21:08:44 -0000	1.3
+++ _conversions.c	4 Dec 2006 07:06:59 -0000	1.3.2.1
@@ -5,5 +5,6 @@
 
 static PyObject *PyBoolean_Type;
-static PyCFunction PyBoolean_New;
+static PyObject *PyBoolean_False;
+static PyObject *PyBoolean_True;
 static PyObject *PyNumber_NaN;
 
@@ -47,8 +48,8 @@
     case ELEMENT_NODE: 
       if (node_descendants(child, descendants) == NULL) {
-	Py_DECREF(nodeType);
-	Py_DECREF(child);
-	Py_DECREF(childNodes);
-	return NULL;
+        Py_DECREF(nodeType);
+        Py_DECREF(child);
+        Py_DECREF(childNodes);
+        return NULL;
       }
       break;
@@ -56,8 +57,8 @@
       data = PyObject_GetAttrString(child, "data");
       if (data == NULL) {
-	Py_DECREF(nodeType);
-	Py_DECREF(child);
-	Py_DECREF(childNodes);
-	return NULL;
+        Py_DECREF(nodeType);
+        Py_DECREF(child);
+        Py_DECREF(childNodes);
+        return NULL;
       }
       PyList_Append(descendants, data);
@@ -97,4 +98,5 @@
     break;
   case ATTRIBUTE_NODE:
+  case XPATH_NAMESPACE_NODE:
     result = PyObject_GetAttrString(node, "value");
     break;
@@ -130,24 +132,24 @@
     if (PyNumber_Finite(object)) {
       if (floor(d) == d) {
-	/* Format as integer */
-	PyObject *num = PyNumber_Long(object);
-	if (!num)
-	  return NULL;
-	result = PyObject_Unicode(num);
-	Py_DECREF(num);
+        /* Format as integer */
+        PyObject *num = PyNumber_Long(object);
+        if (!num)
+          return NULL;
+        result = PyObject_Unicode(num);
+        Py_DECREF(num);
       } 
       else {
-	/* worst case length calc to ensure no buffer overrun:
-	   fmt = %#.<prec>g
-	   buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp for 
-	                                          any double rep.) 
-	   len = 1 + prec + 1 + 2 + 5 = 9 + prec
-	   If prec=0 the effective precision is 1 (the leading digit is
-	   always given), therefore increase by one to 10+prec. 
-	*/
-	char buf[32]; /* only 10 + 12 + '\0' is needed, more than enough */
-	int len;
-	len = sprintf(buf, "%0.12g", d);
-	result = PyUnicode_DecodeASCII(buf, len, "strict");
+        /* worst case length calc to ensure no buffer overrun:
+           fmt = %#.<prec>g
+           buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp for 
+                                                  any double rep.) 
+           len = 1 + prec + 1 + 2 + 5 = 9 + prec
+           If prec=0 the effective precision is 1 (the leading digit is
+           always given), therefore increase by one to 10+prec. 
+        */
+        char buf[32]; /* only 10 + 12 + '\0' is needed, more than enough */
+        int len;
+        len = sprintf(buf, "%0.12g", d);
+        result = PyUnicode_DecodeASCII(buf, len, "strict");
       }
     }
@@ -164,5 +166,5 @@
 
   else if (PyBoolean_Check(object)) {
-    if (PyObject_IsTrue(object)) 
+    if (PyObject_IsTrue(object))
       result = PyUnicode_DecodeASCII("true", 4, "strict");
     else
@@ -193,4 +195,9 @@
 }
 
+static char string_doc[] = 
+"StringValue(object) -> XPath string\n\
+\n\
+Implementation of the XPath 1.0 Recommendation's string function";
+
 static PyObject *StringValue(PyObject *self, PyObject *args)
 {
@@ -203,4 +210,9 @@
 }
 
+static char number_doc[] = 
+"NumberValue(object) -> XPath number\n\
+\n\
+Implementation of the XPath 1.0 Recommendation's number function";
+
 static PyObject *NumberValue(PyObject *self, PyObject *args)
 {
@@ -231,8 +243,12 @@
 }
 
+static char boolean_doc[] = 
+"BooleanValue(object) -> XPath boolean\n\
+\n\
+Implementation of the XPath 1.0 Recommendation's boolean function";
+
 static PyObject *BooleanValue(PyObject *self, PyObject *args)
 {
-  PyObject *object;
-  PyObject *result = NULL;
+  PyObject *object, *result;
 
   if (!PyArg_ParseTuple(args, "O:BooleanValue", &object))
@@ -240,34 +256,33 @@
   
   if (PyBoolean_Check(object)) {
-    Py_INCREF(object);
     result = object;
-  }
-  else if (PyFloat_Check(object) || PyInt_Check(object) ||
-	   PyLong_Check(object) || PySequence_Check(object)) {
-    PyObject *tuple = Py_BuildValue("(O)", object);
-    result = PyBoolean_New(NULL, tuple);
-    Py_XDECREF(tuple);
-  }
-  else {
-    PyObject *strval = object_to_string(object);
-    if (strval != NULL) {
-      PyObject *tuple = Py_BuildValue("(O)", object);
-      result = PyBoolean_New(NULL, tuple);
-      Py_XDECREF(tuple);
-      Py_DECREF(strval);
+  } else if (PyNumber_IsNaN(object)) {
+    result = PyBoolean_False;
+  } else {
+    /* use Python's boolean rules (the same as XPath primitive types) */
+    switch (PyObject_IsTrue(object)) {
+    case 0:
+      result = PyBoolean_False;
+      break;
+    case 1:
+      result = PyBoolean_True;
+      break;
+    default:
+      return NULL;
     }
   }
+  Py_INCREF(result);
   return result;
 }
 
 static PyMethodDef conversions[] = {
-     { "StringValue", StringValue, METH_VARARGS },
-     { "NumberValue", NumberValue, METH_VARARGS },
-     { "BooleanValue", BooleanValue, METH_VARARGS },
-     { NULL, NULL }
+  { "StringValue", StringValue, METH_VARARGS, string_doc },
+  { "NumberValue", NumberValue, METH_VARARGS, number_doc },
+  { "BooleanValue", BooleanValue, METH_VARARGS, boolean_doc },
+  { NULL, NULL }
 };
 
 DL_EXPORT(void) init_conversions(void) {
-  PyObject *module, *method;
+  PyObject *module;
 
   module = Py_InitModule("_conversions", conversions);
@@ -285,9 +300,8 @@
   PyBoolean_Type = PyObject_GetAttrString(module, "BooleanType");
   if (PyBoolean_Type == NULL) return;
-
-  method = PyObject_GetAttrString(module, "bool");
-  if (method == NULL) return;
-  PyBoolean_New = PyCFunction_GetFunction(method);
-  if (PyBoolean_New == NULL) return;
+  PyBoolean_False = PyObject_GetAttrString(module, "false");
+  if (PyBoolean_False == NULL) return;
+  PyBoolean_True = PyObject_GetAttrString(module, "true");
+  if (PyBoolean_True == NULL) return;
   Py_DECREF(module);
 }
--- de.po DELETED ---
--- en_US.po DELETED ---


More information about the 4suite-checkins mailing list