sbsv2/raptor/python/pyparsing.py
author Richard Taylor <richard.i.taylor@nokia.com>
Thu, 04 Mar 2010 13:11:14 +0000
changeset 303 502501837ac4
parent 3 e1eecf4d390d
permissions -rw-r--r--
version 2.12.4 (candidate 2)
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     1
# module pyparsing.py
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     2
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     3
# Copyright (c) 2003-2006  Paul T. McGuire
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     4
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     5
# Permission is hereby granted, free of charge, to any person obtaining
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     6
# a copy of this software and associated documentation files (the
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     7
# "Software"), to deal in the Software without restriction, including
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     8
# without limitation the rights to use, copy, modify, merge, publish,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
     9
# distribute, sublicense, and/or sell copies of the Software, and to
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    10
# permit persons to whom the Software is furnished to do so, subject to
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    11
# the following conditions:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    12
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    13
# The above copyright notice and this permission notice shall be
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    14
# included in all copies or substantial portions of the Software.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    15
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    16
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    17
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    18
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    19
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    20
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    21
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    22
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    23
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    24
#from __future__ import generators
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    25
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    26
__doc__ = \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    27
"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    28
pyparsing module - Classes and methods to define and execute parsing grammars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    29
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    30
The pyparsing module is an alternative approach to creating and executing simple grammars, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    31
vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    32
don't need to learn a new syntax for defining grammars or matching expressions - the parsing module 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    33
provides a library of classes that you use to construct the grammar directly in Python.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    34
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    35
Here is a program to parse "Hello, World!" (or any greeting of the form "<salutation>, <addressee>!")::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    36
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    37
    from pyparsing import Word, alphas
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    38
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    39
    # define grammar of a greeting
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    40
    greet = Word( alphas ) + "," + Word( alphas ) + "!" 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    41
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    42
    hello = "Hello, World!"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    43
    print hello, "->", greet.parseString( hello )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    44
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    45
The program outputs the following::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    46
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    47
    Hello, World! -> ['Hello', ',', 'World', '!']
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    48
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    49
The Python representation of the grammar is quite readable, owing to the self-explanatory 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    50
class names, and the use of '+', '|' and '^' operators.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    51
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    52
The parsed results returned from parseString() can be accessed as a nested list, a dictionary, or an 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    53
object with named attributes.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    54
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    55
The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    56
 - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    57
 - quoted strings
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    58
 - embedded comments
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    59
"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    60
__version__ = "1.4.5"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    61
__versionTime__ = "16 December 2006 07:20"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    62
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    63
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    64
import string
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    65
import copy,sys
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    66
import warnings
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    67
import re
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    68
import sre_constants
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    69
import xml.sax.saxutils
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    70
#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    71
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    72
def _ustr(obj):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    73
    """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    74
       str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    75
       then < returns the unicode object | encodes it with the default encoding | ... >.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    76
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    77
    try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    78
        # If this works, then _ustr(obj) has the same behaviour as str(obj), so
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    79
        # it won't break any existing code.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    80
        return str(obj)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    81
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    82
    except UnicodeEncodeError, e:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    83
        # The Python docs (http://docs.python.org/ref/customization.html#l2h-182)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    84
        # state that "The return value must be a string object". However, does a
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    85
        # unicode object (being a subclass of basestring) count as a "string
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    86
        # object"?
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    87
        # If so, then return a unicode object:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    88
        return unicode(obj)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    89
        # Else encode it... but how? There are many choices... :)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    90
        # Replace unprintables with escape codes?
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    91
        #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors')
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    92
        # Replace unprintables with question marks?
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    93
        #return unicode(obj).encode(sys.getdefaultencoding(), 'replace')
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    94
        # ...
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    95
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    96
def _str2dict(strg):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    97
    return dict( [(c,0) for c in strg] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    98
    #~ return set( [c for c in strg] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
    99
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   100
class _Constants(object):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   101
    pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   102
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   103
alphas     = string.lowercase + string.uppercase
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   104
nums       = string.digits
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   105
hexnums    = nums + "ABCDEFabcdef"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   106
alphanums  = alphas + nums    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   107
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   108
class ParseBaseException(Exception):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   109
    """base exception class for all parsing runtime exceptions"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   110
    __slots__ = ( "loc","msg","pstr","parserElement" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   111
    # Performance tuning: we construct a *lot* of these, so keep this
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   112
    # constructor as small and fast as possible        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   113
    def __init__( self, pstr, loc, msg, elem=None ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   114
        self.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   115
        self.msg = msg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   116
        self.pstr = pstr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   117
        self.parserElement = elem
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   118
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   119
    def __getattr__( self, aname ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   120
        """supported attributes by name are:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   121
            - lineno - returns the line number of the exception text
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   122
            - col - returns the column number of the exception text
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   123
            - line - returns the line containing the exception text
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   124
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   125
        if( aname == "lineno" ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   126
            return lineno( self.loc, self.pstr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   127
        elif( aname in ("col", "column") ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   128
            return col( self.loc, self.pstr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   129
        elif( aname == "line" ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   130
            return line( self.loc, self.pstr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   131
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   132
            raise AttributeError, aname
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   133
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   134
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   135
        return "%s (at char %d), (line:%d, col:%d)" % ( self.msg, self.loc, self.lineno, self.column )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   136
    def __repr__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   137
        return _ustr(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   138
    def markInputline( self, markerString = ">!<" ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   139
        """Extracts the exception line from the input string, and marks 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   140
           the location of the exception with a special symbol.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   141
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   142
        line_str = self.line
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   143
        line_column = self.column - 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   144
        if markerString:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   145
            line_str = "".join( [line_str[:line_column], markerString, line_str[line_column:]])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   146
        return line_str.strip()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   147
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   148
class ParseException(ParseBaseException):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   149
    """exception thrown when parse expressions don't match class"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   150
    """supported attributes by name are:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   151
        - lineno - returns the line number of the exception text
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   152
        - col - returns the column number of the exception text
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   153
        - line - returns the line containing the exception text
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   154
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   155
    pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   156
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   157
class ParseFatalException(ParseBaseException):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   158
    """user-throwable exception thrown when inconsistent parse content
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   159
       is found; stops all parsing immediately"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   160
    pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   161
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   162
class ReparseException(ParseBaseException):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   163
    def __init_( self, newstring, restartLoc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   164
        self.newParseText = newstring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   165
        self.reparseLoc = restartLoc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   166
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   167
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   168
class RecursiveGrammarException(Exception):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   169
    """exception thrown by validate() if the grammar could be improperly recursive"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   170
    def __init__( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   171
        self.parseElementTrace = parseElementList
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   172
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   173
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   174
        return "RecursiveGrammarException: %s" % self.parseElementTrace
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   175
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   176
class ParseResults(object):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   177
    """Structured parse results, to provide multiple means of access to the parsed data:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   178
       - as a list (len(results))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   179
       - by list index (results[0], results[1], etc.)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   180
       - by attribute (results.<resultsName>)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   181
       """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   182
    __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   183
    def __new__(cls, toklist, name=None, asList=True, modal=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   184
        if isinstance(toklist, cls):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   185
            return toklist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   186
        retobj = object.__new__(cls)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   187
        retobj.__doinit = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   188
        return retobj
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   189
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   190
    # Performance tuning: we construct a *lot* of these, so keep this
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   191
    # constructor as small and fast as possible
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   192
    def __init__( self, toklist, name=None, asList=True, modal=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   193
        if self.__doinit:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   194
            self.__doinit = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   195
            self.__name = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   196
            self.__parent = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   197
            self.__accumNames = {}
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   198
            if isinstance(toklist, list):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   199
                self.__toklist = toklist[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   200
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   201
                self.__toklist = [toklist]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   202
            self.__tokdict = dict()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   203
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   204
        # this line is related to debugging the asXML bug
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   205
        #~ asList = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   206
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   207
        if name:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   208
            if not modal:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   209
                self.__accumNames[name] = 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   210
            if isinstance(name,int):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   211
                name = _ustr(name) # will always return a str, but use _ustr for consistency
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   212
            self.__name = name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   213
            if not toklist in (None,'',[]):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   214
                if isinstance(toklist,basestring): 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   215
                    toklist = [ toklist ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   216
                if asList:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   217
                    if isinstance(toklist,ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   218
                        self[name] = (toklist.copy(),-1)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   219
                    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   220
                        self[name] = (ParseResults(toklist[0]),-1)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   221
                    self[name].__name = name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   222
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   223
                    try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   224
                        self[name] = toklist[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   225
                    except (KeyError,TypeError):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   226
                        self[name] = toklist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   227
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   228
    def __getitem__( self, i ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   229
        if isinstance( i, (int,slice) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   230
            return self.__toklist[i]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   231
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   232
            if i not in self.__accumNames:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   233
                return self.__tokdict[i][-1][0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   234
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   235
                return ParseResults([ v[0] for v in self.__tokdict[i] ])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   236
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   237
    def __setitem__( self, k, v ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   238
        if isinstance(v,tuple):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   239
            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   240
            sub = v[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   241
        elif isinstance(k,int):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   242
            self.__toklist[k] = v
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   243
            sub = v
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   244
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   245
            self.__tokdict[k] = self.__tokdict.get(k,list()) + [(v,0)]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   246
            sub = v
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   247
        if isinstance(sub,ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   248
            sub.__parent = self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   249
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   250
    def __delitem__( self, i ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   251
        if isinstance(i,(int,slice)):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   252
            del self.__toklist[i]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   253
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   254
            del self._tokdict[i]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   255
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   256
    def __contains__( self, k ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   257
        return self.__tokdict.has_key(k)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   258
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   259
    def __len__( self ): return len( self.__toklist )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   260
    def __nonzero__( self ): return len( self.__toklist ) > 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   261
    def __iter__( self ): return iter( self.__toklist )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   262
    def keys( self ): 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   263
        """Returns all named result keys."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   264
        return self.__tokdict.keys()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   265
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   266
    def items( self ): 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   267
        """Returns all named result keys and values as a list of tuples."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   268
        return [(k,self[k]) for k in self.__tokdict.keys()]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   269
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   270
    def values( self ): 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   271
        """Returns all named result values."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   272
        return [ v[-1][0] for v in self.__tokdict.values() ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   273
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   274
    def __getattr__( self, name ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   275
        if name not in self.__slots__:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   276
            if self.__tokdict.has_key( name ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   277
                if name not in self.__accumNames:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   278
                    return self.__tokdict[name][-1][0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   279
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   280
                    return ParseResults([ v[0] for v in self.__tokdict[name] ])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   281
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   282
                return ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   283
        return None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   284
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   285
    def __add__( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   286
        ret = self.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   287
        ret += other
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   288
        return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   289
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   290
    def __iadd__( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   291
        if other.__tokdict:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   292
            offset = len(self.__toklist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   293
            addoffset = ( lambda a: (a<0 and offset) or (a+offset) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   294
            otheritems = other.__tokdict.items()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   295
            otherdictitems = [(k,(v[0],addoffset(v[1])) ) for (k,vlist) in otheritems for v in vlist]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   296
            for k,v in otherdictitems:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   297
                self[k] = v
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   298
                if isinstance(v[0],ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   299
                    v[0].__parent = self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   300
        self.__toklist += other.__toklist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   301
        self.__accumNames.update( other.__accumNames )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   302
        del other
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   303
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   304
       
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   305
    def __repr__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   306
        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   307
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   308
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   309
        out = "["
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   310
        sep = ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   311
        for i in self.__toklist:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   312
            if isinstance(i, ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   313
                out += sep + _ustr(i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   314
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   315
                out += sep + repr(i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   316
            sep = ", "
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   317
        out += "]"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   318
        return out
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   319
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   320
    def _asStringList( self, sep='' ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   321
        out = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   322
        for item in self.__toklist:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   323
            if out and sep:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   324
                out.append(sep)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   325
            if isinstance( item, ParseResults ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   326
                out += item._asStringList()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   327
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   328
                out.append( _ustr(item) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   329
        return out
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   330
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   331
    def asList( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   332
        """Returns the parse results as a nested list of matching tokens, all converted to strings."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   333
        out = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   334
        for res in self.__toklist:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   335
            if isinstance(res,ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   336
                out.append( res.asList() )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   337
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   338
                out.append( res )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   339
        return out
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   340
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   341
    def asDict( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   342
        """Returns the named parse results as dictionary."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   343
        return dict( self.items() )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   344
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   345
    def copy( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   346
        """Returns a new copy of a ParseResults object."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   347
        ret = ParseResults( self.__toklist )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   348
        ret.__tokdict = self.__tokdict.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   349
        ret.__parent = self.__parent
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   350
        ret.__accumNames.update( self.__accumNames )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   351
        ret.__name = self.__name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   352
        return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   353
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   354
    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   355
        """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   356
        nl = "\n"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   357
        out = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   358
        namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items() for v in vlist ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   359
        nextLevelIndent = indent + "  "
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   360
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   361
        # collapse out indents if formatting is not desired
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   362
        if not formatted:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   363
            indent = ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   364
            nextLevelIndent = ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   365
            nl = ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   366
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   367
        selfTag = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   368
        if doctag is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   369
            selfTag = doctag
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   370
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   371
            if self.__name:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   372
                selfTag = self.__name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   373
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   374
        if not selfTag:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   375
            if namedItemsOnly:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   376
                return ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   377
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   378
                selfTag = "ITEM"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   379
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   380
        out += [ nl, indent, "<", selfTag, ">" ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   381
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   382
        worklist = self.__toklist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   383
        for i,res in enumerate(worklist):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   384
            if isinstance(res,ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   385
                if i in namedItems:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   386
                    out += [ res.asXML(namedItems[i], namedItemsOnly and doctag is None, nextLevelIndent,formatted)]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   387
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   388
                    out += [ res.asXML(None, namedItemsOnly and doctag is None, nextLevelIndent,formatted)]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   389
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   390
                # individual token, see if there is a name for it
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   391
                resTag = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   392
                if i in namedItems:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   393
                    resTag = namedItems[i]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   394
                if not resTag:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   395
                    if namedItemsOnly:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   396
                        continue
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   397
                    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   398
                        resTag = "ITEM"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   399
                xmlBodyText = xml.sax.saxutils.escape(_ustr(res))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   400
                out += [ nl, nextLevelIndent, "<", resTag, ">", xmlBodyText, "</", resTag, ">" ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   401
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   402
        out += [ nl, indent, "</", selfTag, ">" ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   403
        return "".join(out)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   404
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   405
    def __lookup(self,sub):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   406
        for k,vlist in self.__tokdict.items():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   407
            for v,loc in vlist:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   408
                if sub is v:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   409
                    return k
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   410
        return None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   411
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   412
    def getName(self):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   413
        """Returns the results name for this token expression."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   414
        if self.__name:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   415
            return self.__name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   416
        elif self.__parent:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   417
            par = self.__parent
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   418
            if par:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   419
                return par.__lookup(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   420
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   421
                return None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   422
        elif (len(self) == 1 and 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   423
               len(self.__tokdict) == 1 and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   424
               self.__tokdict.values()[0][0][1] in (0,-1)):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   425
            return self.__tokdict.keys()[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   426
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   427
            return None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   428
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   429
    def dump(self,indent='',depth=0):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   430
        """Diagnostic method for listing out the contents of a ParseResults.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   431
           Accepts an optional indent argument so that this string can be embedded
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   432
           in a nested display of other data."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   433
        out = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   434
        out.append( indent+str(self.asList()) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   435
        keys = self.items()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   436
        keys.sort()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   437
        for k,v in keys:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   438
            if out:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   439
                out.append('\n')
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   440
            out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   441
            if isinstance(v,ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   442
                if v.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   443
                    #~ out.append('\n')
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   444
                    out.append( v.dump(indent,depth+1) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   445
                    #~ out.append('\n')
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   446
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   447
                    out.append(str(v))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   448
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   449
                out.append(str(v))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   450
        #~ out.append('\n')
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   451
        return "".join(out)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   452
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   453
    # add support for pickle protocol
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   454
    def __getstate__(self):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   455
        return ( self.__toklist,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   456
                 ( self.__tokdict.copy(),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   457
                   self.__parent,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   458
                   self.__accumNames,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   459
                   self.__name ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   460
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   461
    def __setstate__(self,state):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   462
        self.__toklist = state[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   463
        self.__tokdict, \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   464
        self.__parent, \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   465
        inAccumNames, \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   466
        self.__name = state[1]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   467
        self.__accumNames = {}
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   468
        self.__accumNames.update(inAccumNames)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   469
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   470
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   471
def col (loc,strg):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   472
    """Returns current column within a string, counting newlines as line separators.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   473
   The first column is number 1.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   474
   """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   475
    return (loc<len(strg) and strg[loc] == '\n') and 1 or loc - strg.rfind("\n", 0, loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   476
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   477
def lineno(loc,strg):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   478
    """Returns current line number within a string, counting newlines as line separators.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   479
   The first line is number 1.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   480
   """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   481
    return strg.count("\n",0,loc) + 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   482
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   483
def line( loc, strg ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   484
    """Returns the line of text containing loc within a string, counting newlines as line separators.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   485
       """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   486
    lastCR = strg.rfind("\n", 0, loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   487
    nextCR = strg.find("\n", loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   488
    if nextCR > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   489
        return strg[lastCR+1:nextCR]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   490
    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   491
        return strg[lastCR+1:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   492
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   493
def _defaultStartDebugAction( instring, loc, expr ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   494
    print "Match",expr,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   495
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   496
def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   497
    print "Matched",expr,"->",toks.asList()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   498
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   499
def _defaultExceptionDebugAction( instring, loc, expr, exc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   500
    print "Exception raised:", exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   501
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   502
def nullDebugAction(*args):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   503
    """'Do-nothing' debug action, to suppress debugging output during parsing."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   504
    pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   505
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   506
class ParserElement(object):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   507
    """Abstract base level parser element class."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   508
    DEFAULT_WHITE_CHARS = " \n\t\r"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   509
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   510
    def setDefaultWhitespaceChars( chars ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   511
        """Overrides the default whitespace chars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   512
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   513
        ParserElement.DEFAULT_WHITE_CHARS = chars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   514
    setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   515
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   516
    def __init__( self, savelist=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   517
        self.parseAction = list()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   518
        self.failAction = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   519
        #~ self.name = "<unknown>"  # don't define self.name, let subclasses try/except upcall
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   520
        self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   521
        self.resultsName = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   522
        self.saveAsList = savelist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   523
        self.skipWhitespace = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   524
        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   525
        self.copyDefaultWhiteChars = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   526
        self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   527
        self.keepTabs = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   528
        self.ignoreExprs = list()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   529
        self.debug = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   530
        self.streamlined = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   531
        self.mayIndexError = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   532
        self.errmsg = ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   533
        self.modalResults = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   534
        self.debugActions = ( None, None, None )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   535
        self.re = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   536
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   537
    def copy( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   538
        """Make a copy of this ParserElement.  Useful for defining different parse actions
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   539
           for the same parsing pattern, using copies of the original parse element."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   540
        cpy = copy.copy( self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   541
        cpy.parseAction = self.parseAction[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   542
        cpy.ignoreExprs = self.ignoreExprs[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   543
        if self.copyDefaultWhiteChars:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   544
            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   545
        return cpy
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   546
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   547
    def setName( self, name ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   548
        """Define name for this expression, for use in debugging."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   549
        self.name = name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   550
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   551
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   552
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   553
    def setResultsName( self, name, listAllMatches=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   554
        """Define name for referencing matching tokens as a nested attribute 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   555
           of the returned parse results.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   556
           NOTE: this returns a *copy* of the original ParserElement object;
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   557
           this is so that the client can define a basic element, such as an
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   558
           integer, and reference it in multiple places with different names.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   559
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   560
        newself = self.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   561
        newself.resultsName = name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   562
        newself.modalResults = not listAllMatches
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   563
        return newself
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   564
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   565
    def normalizeParseActionArgs( f ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   566
        """Internal method used to decorate parse actions that take fewer than 3 arguments,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   567
           so that all parse actions can be called as f(s,l,t)."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   568
        STAR_ARGS = 4
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   569
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   570
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   571
            restore = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   572
            if isinstance(f,type):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   573
                restore = f
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   574
                f = f.__init__
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   575
            if f.func_code.co_flags & STAR_ARGS:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   576
                return f
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   577
            numargs = f.func_code.co_argcount
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   578
            if hasattr(f,"im_self"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   579
                numargs -= 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   580
            if restore:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   581
                f = restore
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   582
        except AttributeError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   583
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   584
                # not a function, must be a callable object, get info from the
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   585
                # im_func binding of its bound __call__ method
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   586
                if f.__call__.im_func.func_code.co_flags & STAR_ARGS:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   587
                    return f
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   588
                numargs = f.__call__.im_func.func_code.co_argcount
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   589
                if hasattr(f.__call__,"im_self"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   590
                    numargs -= 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   591
            except AttributeError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   592
                # not a bound method, get info directly from __call__ method
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   593
                if f.__call__.func_code.co_flags & STAR_ARGS:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   594
                    return f
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   595
                numargs = f.__call__.func_code.co_argcount
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   596
                if hasattr(f.__call__,"im_self"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   597
                    numargs -= 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   598
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   599
        #~ print "adding function %s with %d args" % (f.func_name,numargs)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   600
        if numargs == 3:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   601
            return f
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   602
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   603
            if numargs == 2:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   604
                def tmp(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   605
                    return f(l,t)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   606
            elif numargs == 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   607
                def tmp(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   608
                    return f(t)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   609
            else: #~ numargs == 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   610
                def tmp(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   611
                    return f()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   612
            return tmp
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   613
    normalizeParseActionArgs = staticmethod(normalizeParseActionArgs)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   614
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   615
    def setParseAction( self, *fns ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   616
        """Define action to perform when successfully matching parse element definition.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   617
           Parse action fn is a callable method with 0-3 arguments, called as fn(s,loc,toks),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   618
           fn(loc,toks), fn(toks), or just fn(), where:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   619
            - s   = the original string being parsed
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   620
            - loc = the location of the matching substring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   621
            - toks = a list of the matched tokens, packaged as a ParseResults object
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   622
           If the functions in fns modify the tokens, they can return them as the return
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   623
           value from fn, and the modified list of tokens will replace the original.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   624
           Otherwise, fn does not need to return any value."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   625
        self.parseAction = map(self.normalizeParseActionArgs, list(fns))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   626
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   627
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   628
    def addParseAction( self, *fns ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   629
        """Add parse action to expression's list of parse actions. See setParseAction_."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   630
        self.parseAction += map(self.normalizeParseActionArgs, list(fns))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   631
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   632
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   633
    def setFailAction( self, fn ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   634
        """Define action to perform if parsing fails at this expression. 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   635
           Fail acton fn is a callable function that takes the arguments 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   636
           fn(s,loc,expr,err) where:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   637
            - s = string being parsed
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   638
            - loc = location where expression match was attempted and failed
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   639
            - expr = the parse expression that failed
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   640
            - err = the exception thrown
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   641
           The function returns no value.  It may throw ParseFatalException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   642
           if it is desired to stop parsing immediately."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   643
        self.failAction = fn
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   644
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   645
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   646
    def skipIgnorables( self, instring, loc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   647
        exprsFound = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   648
        while exprsFound:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   649
            exprsFound = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   650
            for e in self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   651
                try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   652
                    while 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   653
                        loc,dummy = e._parse( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   654
                        exprsFound = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   655
                except ParseException:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   656
                    pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   657
        return loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   658
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   659
    def preParse( self, instring, loc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   660
        if self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   661
            loc = self.skipIgnorables( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   662
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   663
        if self.skipWhitespace:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   664
            wt = self.whiteChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   665
            instrlen = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   666
            while loc < instrlen and instring[loc] in wt:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   667
                loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   668
                
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   669
        return loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   670
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   671
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   672
        return loc, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   673
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   674
    def postParse( self, instring, loc, tokenlist ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   675
        return tokenlist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   676
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   677
    #~ @profile
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   678
    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   679
        debugging = ( self.debug ) #and doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   680
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   681
        if debugging or self.failAction:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   682
            #~ print "Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   683
            if (self.debugActions[0] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   684
                self.debugActions[0]( instring, loc, self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   685
            if callPreParse:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   686
                preloc = self.preParse( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   687
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   688
                preloc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   689
            tokensStart = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   690
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   691
                try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   692
                    loc,tokens = self.parseImpl( instring, preloc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   693
                except IndexError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   694
                    raise ParseException( instring, len(instring), self.errmsg, self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   695
            #~ except ReparseException, retryEx:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   696
                #~ pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   697
            except ParseException, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   698
                #~ print "Exception raised:", err
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   699
                if self.debugActions[2]:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   700
                    self.debugActions[2]( instring, tokensStart, self, err )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   701
                if self.failAction:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   702
                    self.failAction( instring, tokensStart, self, err )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   703
                raise
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   704
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   705
            if callPreParse:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   706
                preloc = self.preParse( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   707
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   708
                preloc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   709
            tokensStart = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   710
            if self.mayIndexError or loc >= len(instring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   711
                try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   712
                    loc,tokens = self.parseImpl( instring, preloc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   713
                except IndexError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   714
                    raise ParseException( instring, len(instring), self.errmsg, self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   715
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   716
                loc,tokens = self.parseImpl( instring, preloc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   717
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   718
        tokens = self.postParse( instring, loc, tokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   719
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   720
        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   721
        if self.parseAction and doActions:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   722
            if debugging:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   723
                try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   724
                    for fn in self.parseAction:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   725
                        tokens = fn( instring, tokensStart, retTokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   726
                        if tokens is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   727
                            retTokens = ParseResults( tokens, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   728
                                                      self.resultsName, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   729
                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   730
                                                      modal=self.modalResults )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   731
                except ParseException, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   732
                    #~ print "Exception raised in user parse action:", err
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   733
                    if (self.debugActions[2] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   734
                        self.debugActions[2]( instring, tokensStart, self, err )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   735
                    raise
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   736
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   737
                for fn in self.parseAction:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   738
                    tokens = fn( instring, tokensStart, retTokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   739
                    if tokens is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   740
                        retTokens = ParseResults( tokens, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   741
                                                  self.resultsName, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   742
                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   743
                                                  modal=self.modalResults )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   744
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   745
        if debugging:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   746
            #~ print "Matched",self,"->",retTokens.asList()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   747
            if (self.debugActions[1] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   748
                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   749
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   750
        return loc, retTokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   751
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   752
    def tryParse( self, instring, loc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   753
        return self._parse( instring, loc, doActions=False )[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   754
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   755
    # this method gets repeatedly called during backtracking with the same arguments -
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   756
    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   757
    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   758
        if doActions and self.parseAction:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   759
            return self._parseNoCache( instring, loc, doActions, callPreParse )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   760
        lookup = (self,instring,loc,callPreParse)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   761
        if lookup in ParserElement._exprArgCache:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   762
            value = ParserElement._exprArgCache[ lookup ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   763
            if isinstance(value,Exception):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   764
                if isinstance(value,ParseBaseException):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   765
                    value.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   766
                raise value
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   767
            return value
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   768
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   769
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   770
                ParserElement._exprArgCache[ lookup ] = \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   771
                    value = self._parseNoCache( instring, loc, doActions, callPreParse )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   772
                return value
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   773
            except ParseBaseException, pe:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   774
                ParserElement._exprArgCache[ lookup ] = pe
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   775
                raise
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   776
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   777
    _parse = _parseNoCache
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   778
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   779
    # argument cache for optimizing repeated calls when backtracking through recursive expressions
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   780
    _exprArgCache = {}
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   781
    def resetCache():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   782
        ParserElement._exprArgCache.clear()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   783
    resetCache = staticmethod(resetCache)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   784
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   785
    _packratEnabled = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   786
    def enablePackrat():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   787
        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   788
           Repeated parse attempts at the same string location (which happens 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   789
           often in many complex grammars) can immediately return a cached value, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   790
           instead of re-executing parsing/validating code.  Memoizing is done of
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   791
           both valid results and parsing exceptions.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   792
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   793
           This speedup may break existing programs that use parse actions that 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   794
           have side-effects.  For this reason, packrat parsing is disabled when
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   795
           you first import pyparsing.  To activate the packrat feature, your
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   796
           program must call the class method ParserElement.enablePackrat().  If
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   797
           your program uses psyco to "compile as you go", you must call 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   798
           enablePackrat before calling psyco.full().  If you do not do this,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   799
           Python will crash.  For best results, call enablePackrat() immediately
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   800
           after importing pyparsing.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   801
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   802
        if not ParserElement._packratEnabled:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   803
            ParserElement._packratEnabled = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   804
            ParserElement._parse = ParserElement._parseCache
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   805
    enablePackrat = staticmethod(enablePackrat)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   806
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   807
    def parseString( self, instring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   808
        """Execute the parse expression with the given string.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   809
           This is the main interface to the client code, once the complete 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   810
           expression has been built.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   811
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   812
        ParserElement.resetCache()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   813
        if not self.streamlined:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   814
            self.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   815
            #~ self.saveAsList = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   816
        for e in self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   817
            e.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   818
        if self.keepTabs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   819
            loc, tokens = self._parse( instring, 0 )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   820
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   821
            loc, tokens = self._parse( instring.expandtabs(), 0 )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   822
        return tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   823
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   824
    def scanString( self, instring, maxMatches=sys.maxint ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   825
        """Scan the input string for expression matches.  Each match will return the 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   826
           matching tokens, start location, and end location.  May be called with optional
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   827
           maxMatches argument, to clip scanning after 'n' matches are found."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   828
        if not self.streamlined:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   829
            self.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   830
        for e in self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   831
            e.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   832
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   833
        if not self.keepTabs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   834
            instring = instring.expandtabs()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   835
        instrlen = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   836
        loc = 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   837
        preparseFn = self.preParse
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   838
        parseFn = self._parse
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   839
        ParserElement.resetCache()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   840
        matches = 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   841
        while loc <= instrlen and matches < maxMatches:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   842
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   843
                preloc = preparseFn( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   844
                nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   845
            except ParseException:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   846
                loc = preloc+1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   847
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   848
                matches += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   849
                yield tokens, preloc, nextLoc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   850
                loc = nextLoc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   851
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   852
    def transformString( self, instring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   853
        """Extension to scanString, to modify matching text with modified tokens that may
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   854
           be returned from a parse action.  To use transformString, define a grammar and 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   855
           attach a parse action to it that modifies the returned token list.  
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   856
           Invoking transformString() on a target string will then scan for matches, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   857
           and replace the matched text patterns according to the logic in the parse 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   858
           action.  transformString() returns the resulting transformed string."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   859
        out = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   860
        lastE = 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   861
        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   862
        # keep string locs straight between transformString and scanString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   863
        self.keepTabs = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   864
        for t,s,e in self.scanString( instring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   865
            out.append( instring[lastE:s] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   866
            if t:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   867
                if isinstance(t,ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   868
                    out += t.asList()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   869
                elif isinstance(t,list):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   870
                    out += t
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   871
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   872
                    out.append(t)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   873
            lastE = e
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   874
        out.append(instring[lastE:])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   875
        return "".join(out)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   876
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   877
    def searchString( self, instring, maxMatches=sys.maxint ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   878
        """Another extension to scanString, simplifying the access to the tokens found
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   879
           to match the given parse expression.  May be called with optional
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   880
           maxMatches argument, to clip searching after 'n' matches are found.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   881
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   882
        return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   883
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   884
    def __add__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   885
        """Implementation of + operator - returns And"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   886
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   887
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   888
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   889
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   890
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   891
        return And( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   892
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   893
    def __radd__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   894
        """Implementation of += operator"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   895
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   896
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   897
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   898
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   899
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   900
        return other + self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   901
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   902
    def __or__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   903
        """Implementation of | operator - returns MatchFirst"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   904
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   905
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   906
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   907
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   908
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   909
        return MatchFirst( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   910
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   911
    def __ror__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   912
        """Implementation of |= operator"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   913
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   914
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   915
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   916
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   917
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   918
        return other | self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   919
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   920
    def __xor__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   921
        """Implementation of ^ operator - returns Or"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   922
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   923
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   924
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   925
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   926
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   927
        return Or( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   928
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   929
    def __rxor__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   930
        """Implementation of ^= operator"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   931
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   932
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   933
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   934
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   935
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   936
        return other ^ self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   937
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   938
    def __and__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   939
        """Implementation of & operator - returns Each"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   940
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   941
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   942
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   943
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   944
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   945
        return Each( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   946
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   947
    def __rand__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   948
        """Implementation of right-& operator"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   949
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   950
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   951
        if not isinstance( other, ParserElement ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   952
            warnings.warn("Cannot add element of type %s to ParserElement" % type(other),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   953
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   954
        return other & self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   955
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   956
    def __invert__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   957
        """Implementation of ~ operator - returns NotAny"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   958
        return NotAny( self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   959
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   960
    def suppress( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   961
        """Suppresses the output of this ParserElement; useful to keep punctuation from
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   962
           cluttering up returned output.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   963
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   964
        return Suppress( self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   965
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   966
    def leaveWhitespace( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   967
        """Disables the skipping of whitespace before matching the characters in the 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   968
           ParserElement's defined pattern.  This is normally only used internally by
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   969
           the pyparsing module, but may be needed in some whitespace-sensitive grammars.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   970
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   971
        self.skipWhitespace = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   972
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   973
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   974
    def setWhitespaceChars( self, chars ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   975
        """Overrides the default whitespace chars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   976
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   977
        self.skipWhitespace = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   978
        self.whiteChars = chars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   979
        self.copyDefaultWhiteChars = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   980
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   981
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   982
    def parseWithTabs( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   983
        """Overrides default behavior to expand <TAB>s to spaces before parsing the input string.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   984
           Must be called before parseString when the input grammar contains elements that 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   985
           match <TAB> characters."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   986
        self.keepTabs = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   987
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   988
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   989
    def ignore( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   990
        """Define expression to be ignored (e.g., comments) while doing pattern 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   991
           matching; may be called repeatedly, to define multiple comment or other
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   992
           ignorable patterns.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   993
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   994
        if isinstance( other, Suppress ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   995
            if other not in self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   996
                self.ignoreExprs.append( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   997
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   998
            self.ignoreExprs.append( Suppress( other ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
   999
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1000
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1001
    def setDebugActions( self, startAction, successAction, exceptionAction ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1002
        """Enable display of debugging messages while doing pattern matching."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1003
        self.debugActions = (startAction or _defaultStartDebugAction, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1004
                             successAction or _defaultSuccessDebugAction, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1005
                             exceptionAction or _defaultExceptionDebugAction)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1006
        self.debug = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1007
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1008
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1009
    def setDebug( self, flag=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1010
        """Enable display of debugging messages while doing pattern matching."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1011
        if flag:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1012
            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1013
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1014
            self.debug = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1015
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1016
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1017
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1018
        return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1019
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1020
    def __repr__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1021
        return _ustr(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1022
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1023
    def streamline( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1024
        self.streamlined = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1025
        self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1026
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1027
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1028
    def checkRecursion( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1029
        pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1030
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1031
    def validate( self, validateTrace=[] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1032
        """Check defined expressions for valid structure, check for infinite recursive definitions."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1033
        self.checkRecursion( [] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1034
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1035
    def parseFile( self, file_or_filename ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1036
        """Execute the parse expression on the given file or filename.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1037
           If a filename is specified (instead of a file object),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1038
           the entire file is opened, read, and closed before parsing.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1039
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1040
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1041
            file_contents = file_or_filename.read()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1042
        except AttributeError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1043
            f = open(file_or_filename, "rb")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1044
            file_contents = f.read()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1045
            f.close()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1046
        return self.parseString(file_contents)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1047
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1048
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1049
class Token(ParserElement):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1050
    """Abstract ParserElement subclass, for defining atomic matching patterns."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1051
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1052
        super(Token,self).__init__( savelist=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1053
        self.myException = ParseException("",0,"",self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1054
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1055
    def setName(self, name):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1056
        s = super(Token,self).setName(name)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1057
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1058
        s.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1059
        return s
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1060
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1061
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1062
class Empty(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1063
    """An empty token, will always match."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1064
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1065
        super(Empty,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1066
        self.name = "Empty"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1067
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1068
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1069
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1070
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1071
class NoMatch(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1072
    """A token that will never match."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1073
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1074
        super(NoMatch,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1075
        self.name = "NoMatch"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1076
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1077
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1078
        self.errmsg = "Unmatchable token"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1079
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1080
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1081
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1082
        exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1083
        exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1084
        exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1085
        raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1086
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1087
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1088
class Literal(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1089
    """Token to exactly match a specified string."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1090
    def __init__( self, matchString ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1091
        super(Literal,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1092
        self.match = matchString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1093
        self.matchLen = len(matchString)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1094
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1095
            self.firstMatchChar = matchString[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1096
        except IndexError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1097
            warnings.warn("null string passed to Literal; use Empty() instead", 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1098
                            SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1099
            self.__class__ = Empty
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1100
        self.name = '"%s"' % self.match
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1101
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1102
        self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1103
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1104
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1105
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1106
    # Performance tuning: this routine gets called a *lot*
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1107
    # if this is a single character match string  and the first character matches,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1108
    # short-circuit as quickly as possible, and avoid calling startswith
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1109
    #~ @profile
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1110
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1111
        if (instring[loc] == self.firstMatchChar and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1112
            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1113
            return loc+self.matchLen, self.match
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1114
        #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1115
        exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1116
        exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1117
        exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1118
        raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1119
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1120
class Keyword(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1121
    """Token to exactly match a specified string as a keyword, that is, it must be 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1122
       immediately followed by a non-keyword character.  Compare with Literal::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1123
         Literal("if") will match the leading 'if' in 'ifAndOnlyIf'.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1124
         Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)'
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1125
       Accepts two optional constructor arguments in addition to the keyword string:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1126
       identChars is a string of characters that would be valid identifier characters,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1127
       defaulting to all alphanumerics + "_" and "$"; caseless allows case-insensitive
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1128
       matching, default is False.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1129
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1130
    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1131
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1132
    def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1133
        super(Keyword,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1134
        self.match = matchString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1135
        self.matchLen = len(matchString)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1136
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1137
            self.firstMatchChar = matchString[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1138
        except IndexError:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1139
            warnings.warn("null string passed to Keyword; use Empty() instead", 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1140
                            SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1141
        self.name = '"%s"' % self.match
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1142
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1143
        self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1144
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1145
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1146
        self.caseless = caseless
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1147
        if caseless:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1148
            self.caselessmatch = matchString.upper()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1149
            identChars = identChars.upper()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1150
        self.identChars = _str2dict(identChars)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1151
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1152
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1153
        if self.caseless:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1154
            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1155
                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1156
                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1157
                return loc+self.matchLen, self.match
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1158
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1159
            if (instring[loc] == self.firstMatchChar and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1160
                (self.matchLen==1 or instring.startswith(self.match,loc)) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1161
                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1162
                (loc == 0 or instring[loc-1] not in self.identChars) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1163
                return loc+self.matchLen, self.match
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1164
        #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1165
        exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1166
        exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1167
        exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1168
        raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1169
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1170
    def copy(self):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1171
        c = super(Keyword,self).copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1172
        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1173
        return c
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1174
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1175
    def setDefaultKeywordChars( chars ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1176
        """Overrides the default Keyword chars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1177
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1178
        Keyword.DEFAULT_KEYWORD_CHARS = chars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1179
    setDefaultKeywordChars = staticmethod(setDefaultKeywordChars)        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1180
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1181
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1182
class CaselessLiteral(Literal):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1183
    """Token to match a specified string, ignoring case of letters.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1184
       Note: the matched results will always be in the case of the given
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1185
       match string, NOT the case of the input text.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1186
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1187
    def __init__( self, matchString ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1188
        super(CaselessLiteral,self).__init__( matchString.upper() )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1189
        # Preserve the defining literal.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1190
        self.returnString = matchString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1191
        self.name = "'%s'" % self.returnString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1192
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1193
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1194
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1195
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1196
        if instring[ loc:loc+self.matchLen ].upper() == self.match:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1197
            return loc+self.matchLen, self.returnString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1198
        #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1199
        exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1200
        exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1201
        exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1202
        raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1203
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1204
class CaselessKeyword(Keyword):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1205
    def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1206
        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1207
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1208
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1209
        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1210
             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1211
            return loc+self.matchLen, self.match
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1212
        #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1213
        exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1214
        exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1215
        exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1216
        raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1217
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1218
class Word(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1219
    """Token for matching words composed of allowed character sets.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1220
       Defined with string containing all allowed initial characters,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1221
       an optional string containing allowed body characters (if omitted,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1222
       defaults to the initial character set), and an optional minimum,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1223
       maximum, and/or exact length.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1224
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1225
    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0 ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1226
        super(Word,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1227
        self.initCharsOrig = initChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1228
        self.initChars = _str2dict(initChars)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1229
        if bodyChars :
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1230
            self.bodyCharsOrig = bodyChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1231
            self.bodyChars = _str2dict(bodyChars)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1232
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1233
            self.bodyCharsOrig = initChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1234
            self.bodyChars = _str2dict(initChars)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1235
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1236
        self.maxSpecified = max > 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1237
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1238
        self.minLen = min
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1239
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1240
        if max > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1241
            self.maxLen = max
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1242
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1243
            self.maxLen = sys.maxint
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1244
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1245
        if exact > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1246
            self.maxLen = exact
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1247
            self.minLen = exact
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1248
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1249
        self.name = _ustr(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1250
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1251
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1252
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1253
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1254
        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1255
            if self.bodyCharsOrig == self.initCharsOrig:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1256
                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1257
            elif len(self.bodyCharsOrig) == 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1258
                self.reString = "%s[%s]*" % \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1259
                                      (re.escape(self.initCharsOrig),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1260
                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1261
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1262
                self.reString = "[%s][%s]*" % \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1263
                                      (_escapeRegexRangeChars(self.initCharsOrig),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1264
                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1265
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1266
                self.re = re.compile( self.reString )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1267
            except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1268
                self.re = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1269
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1270
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1271
        if self.re:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1272
            result = self.re.match(instring,loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1273
            if not result:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1274
                exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1275
                exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1276
                exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1277
                raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1278
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1279
            loc = result.end()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1280
            return loc,result.group()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1281
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1282
        if not(instring[ loc ] in self.initChars):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1283
            #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1284
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1285
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1286
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1287
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1288
        start = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1289
        loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1290
        instrlen = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1291
        bodychars = self.bodyChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1292
        maxloc = start + self.maxLen
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1293
        maxloc = min( maxloc, instrlen )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1294
        while loc < maxloc and instring[loc] in bodychars:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1295
            loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1296
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1297
        throwException = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1298
        if loc - start < self.minLen:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1299
            throwException = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1300
        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1301
            throwException = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1302
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1303
        if throwException:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1304
            #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1305
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1306
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1307
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1308
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1309
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1310
        return loc, instring[start:loc]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1311
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1312
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1313
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1314
            return super(Word,self).__str__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1315
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1316
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1317
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1318
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1319
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1320
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1321
            def charsAsStr(s):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1322
                if len(s)>4:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1323
                    return s[:4]+"..."
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1324
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1325
                    return s
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1326
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1327
            if ( self.initCharsOrig != self.bodyCharsOrig ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1328
                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1329
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1330
                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1331
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1332
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1333
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1334
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1335
class Regex(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1336
    """Token for matching strings that match a given regular expression.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1337
       Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1338
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1339
    def __init__( self, pattern, flags=0):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1340
        """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1341
        super(Regex,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1342
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1343
        if len(pattern) == 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1344
            warnings.warn("null string passed to Regex; use Empty() instead", 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1345
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1346
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1347
        self.pattern = pattern
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1348
        self.flags = flags
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1349
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1350
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1351
            self.re = re.compile(self.pattern, self.flags)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1352
            self.reString = self.pattern
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1353
        except sre_constants.error,e:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1354
            warnings.warn("invalid pattern (%s) passed to Regex" % pattern, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1355
                SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1356
            raise
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1357
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1358
        self.name = _ustr(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1359
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1360
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1361
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1362
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1363
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1364
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1365
        result = self.re.match(instring,loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1366
        if not result:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1367
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1368
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1369
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1370
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1371
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1372
        loc = result.end()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1373
        d = result.groupdict()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1374
        ret = ParseResults(result.group())
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1375
        if d:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1376
            for k in d.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1377
                ret[k] = d[k]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1378
        return loc,ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1379
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1380
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1381
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1382
            return super(Regex,self).__str__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1383
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1384
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1385
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1386
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1387
            self.strRepr = "Re:(%s)" % repr(self.pattern)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1388
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1389
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1390
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1391
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1392
class QuotedString(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1393
    """Token for matching strings that are delimited by quoting characters.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1394
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1395
    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1396
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1397
           Defined with the following parameters:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1398
           - quoteChar - string of one or more characters defining the quote delimiting string
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1399
           - escChar - character to escape quotes, typically backslash (default=None)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1400
           - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1401
           - multiline - boolean indicating whether quotes can span multiple lines (default=False)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1402
           - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1403
           - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1404
        """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1405
        super(QuotedString,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1406
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1407
        # remove white space from quote chars - wont work anyway
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1408
        quoteChar = quoteChar.strip()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1409
        if len(quoteChar) == 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1410
            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1411
            raise SyntaxError()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1412
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1413
        if endQuoteChar is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1414
            endQuoteChar = quoteChar
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1415
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1416
            endQuoteChar = endQuoteChar.strip()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1417
            if len(endQuoteChar) == 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1418
                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1419
                raise SyntaxError()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1420
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1421
        self.quoteChar = quoteChar
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1422
        self.quoteCharLen = len(quoteChar)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1423
        self.firstQuoteChar = quoteChar[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1424
        self.endQuoteChar = endQuoteChar
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1425
        self.endQuoteCharLen = len(endQuoteChar)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1426
        self.escChar = escChar
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1427
        self.escQuote = escQuote
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1428
        self.unquoteResults = unquoteResults
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1429
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1430
        if multiline:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1431
            self.flags = re.MULTILINE | re.DOTALL
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1432
            self.pattern = r'%s(?:[^%s%s]' % \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1433
                ( re.escape(self.quoteChar),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1434
                  _escapeRegexRangeChars(self.endQuoteChar[0]),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1435
                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1436
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1437
            self.flags = 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1438
            self.pattern = r'%s(?:[^%s\n\r%s]' % \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1439
                ( re.escape(self.quoteChar),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1440
                  _escapeRegexRangeChars(self.endQuoteChar[0]),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1441
                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1442
        if len(self.endQuoteChar) > 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1443
            self.pattern += (
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1444
                '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1445
                                               _escapeRegexRangeChars(self.endQuoteChar[i])) 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1446
                                    for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')'
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1447
                )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1448
        if escQuote:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1449
            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1450
        if escChar:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1451
            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1452
            self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1453
        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1454
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1455
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1456
            self.re = re.compile(self.pattern, self.flags)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1457
            self.reString = self.pattern
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1458
        except sre_constants.error,e:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1459
            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1460
                SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1461
            raise
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1462
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1463
        self.name = _ustr(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1464
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1465
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1466
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1467
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1468
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1469
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1470
        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1471
        if not result:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1472
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1473
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1474
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1475
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1476
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1477
        loc = result.end()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1478
        ret = result.group()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1479
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1480
        if self.unquoteResults:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1481
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1482
            # strip off quotes
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1483
            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1484
                
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1485
            if isinstance(ret,basestring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1486
                # replace escaped characters
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1487
                if self.escChar:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1488
                    ret = re.sub(self.escCharReplacePattern,"\g<1>",ret)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1489
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1490
                # replace escaped quotes
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1491
                if self.escQuote:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1492
                    ret = ret.replace(self.escQuote, self.endQuoteChar)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1493
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1494
        return loc, ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1495
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1496
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1497
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1498
            return super(QuotedString,self).__str__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1499
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1500
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1501
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1502
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1503
            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1504
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1505
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1506
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1507
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1508
class CharsNotIn(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1509
    """Token for matching words composed of characters *not* in a given set.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1510
       Defined with string containing all disallowed characters, and an optional 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1511
       minimum, maximum, and/or exact length.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1512
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1513
    def __init__( self, notChars, min=1, max=0, exact=0 ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1514
        super(CharsNotIn,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1515
        self.skipWhitespace = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1516
        self.notChars = notChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1517
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1518
        self.minLen = min
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1519
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1520
        if max > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1521
            self.maxLen = max
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1522
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1523
            self.maxLen = sys.maxint
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1524
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1525
        if exact > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1526
            self.maxLen = exact
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1527
            self.minLen = exact
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1528
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1529
        self.name = _ustr(self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1530
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1531
        self.mayReturnEmpty = ( self.minLen == 0 )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1532
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1533
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1534
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1535
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1536
        if instring[loc] in self.notChars:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1537
            #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1538
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1539
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1540
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1541
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1542
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1543
        start = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1544
        loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1545
        notchars = self.notChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1546
        maxlen = min( start+self.maxLen, len(instring) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1547
        while loc < maxlen and (instring[loc] not in notchars):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1548
            loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1549
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1550
        if loc - start < self.minLen:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1551
            #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1552
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1553
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1554
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1555
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1556
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1557
        return loc, instring[start:loc]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1558
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1559
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1560
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1561
            return super(CharsNotIn, self).__str__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1562
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1563
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1564
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1565
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1566
            if len(self.notChars) > 4:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1567
                self.strRepr = "!W:(%s...)" % self.notChars[:4]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1568
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1569
                self.strRepr = "!W:(%s)" % self.notChars
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1570
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1571
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1572
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1573
class White(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1574
    """Special matching class for matching whitespace.  Normally, whitespace is ignored
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1575
       by pyparsing grammars.  This class is included when some whitespace structures
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1576
       are significant.  Define with a string containing the whitespace characters to be
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1577
       matched; default is " \\t\\n".  Also takes optional min, max, and exact arguments,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1578
       as defined for the Word class."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1579
    whiteStrs = {
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1580
        " " : "<SPC>",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1581
        "\t": "<TAB>",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1582
        "\n": "<LF>",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1583
        "\r": "<CR>",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1584
        "\f": "<FF>",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1585
        }
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1586
    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1587
        super(White,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1588
        self.matchWhite = ws
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1589
        self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1590
        #~ self.leaveWhitespace()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1591
        self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite]))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1592
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1593
        self.errmsg = "Expected " + self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1594
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1595
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1596
        self.minLen = min
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1597
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1598
        if max > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1599
            self.maxLen = max
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1600
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1601
            self.maxLen = sys.maxint
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1602
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1603
        if exact > 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1604
            self.maxLen = exact
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1605
            self.minLen = exact
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1606
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1607
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1608
        if not(instring[ loc ] in self.matchWhite):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1609
            #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1610
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1611
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1612
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1613
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1614
        start = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1615
        loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1616
        maxloc = start + self.maxLen
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1617
        maxloc = min( maxloc, len(instring) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1618
        while loc < maxloc and instring[loc] in self.matchWhite:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1619
            loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1620
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1621
        if loc - start < self.minLen:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1622
            #~ raise ParseException( instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1623
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1624
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1625
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1626
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1627
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1628
        return loc, instring[start:loc]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1629
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1630
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1631
class PositionToken(Token):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1632
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1633
        super(PositionToken,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1634
        self.name=self.__class__.__name__
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1635
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1636
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1637
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1638
class GoToColumn(PositionToken):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1639
    """Token to advance to a specific column of input text; useful for tabular report scraping."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1640
    def __init__( self, colno ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1641
        super(GoToColumn,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1642
        self.col = colno
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1643
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1644
    def preParse( self, instring, loc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1645
        if col(loc,instring) != self.col:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1646
            instrlen = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1647
            if self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1648
                loc = self.skipIgnorables( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1649
            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1650
                loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1651
        return loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1652
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1653
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1654
        thiscol = col( loc, instring )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1655
        if thiscol > self.col:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1656
            raise ParseException( instring, loc, "Text not in expected column", self )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1657
        newloc = loc + self.col - thiscol
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1658
        ret = instring[ loc: newloc ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1659
        return newloc, ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1660
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1661
class LineStart(PositionToken):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1662
    """Matches if current position is at the beginning of a line within the parse string"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1663
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1664
        super(LineStart,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1665
        self.setWhitespaceChars( " \t" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1666
        self.errmsg = "Expected start of line"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1667
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1668
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1669
    def preParse( self, instring, loc ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1670
        preloc = super(LineStart,self).preParse(instring,loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1671
        if instring[preloc] == "\n":
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1672
            loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1673
        return loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1674
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1675
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1676
        if not( loc==0 or
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1677
            (loc == self.preParse( instring, 0 )) or
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1678
            (instring[loc-1] == "\n") ): #col(loc, instring) != 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1679
            #~ raise ParseException( instring, loc, "Expected start of line" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1680
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1681
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1682
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1683
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1684
        return loc, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1685
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1686
class LineEnd(PositionToken):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1687
    """Matches if current position is at the end of a line within the parse string"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1688
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1689
        super(LineEnd,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1690
        self.setWhitespaceChars( " \t" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1691
        self.errmsg = "Expected end of line"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1692
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1693
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1694
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1695
        if loc<len(instring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1696
            if instring[loc] == "\n":
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1697
                return loc+1, "\n"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1698
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1699
                #~ raise ParseException( instring, loc, "Expected end of line" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1700
                exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1701
                exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1702
                exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1703
                raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1704
        elif loc == len(instring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1705
            return loc+1, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1706
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1707
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1708
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1709
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1710
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1711
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1712
class StringStart(PositionToken):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1713
    """Matches if current position is at the beginning of the parse string"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1714
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1715
        super(StringStart,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1716
        self.errmsg = "Expected start of text"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1717
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1718
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1719
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1720
        if loc != 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1721
            # see if entire string up to here is just whitespace and ignoreables
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1722
            if loc != self.preParse( instring, 0 ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1723
                #~ raise ParseException( instring, loc, "Expected start of text" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1724
                exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1725
                exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1726
                exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1727
                raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1728
        return loc, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1729
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1730
class StringEnd(PositionToken):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1731
    """Matches if current position is at the end of the parse string"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1732
    def __init__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1733
        super(StringEnd,self).__init__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1734
        self.errmsg = "Expected end of text"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1735
        self.myException.msg = self.errmsg
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1736
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1737
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1738
        if loc < len(instring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1739
            #~ raise ParseException( instring, loc, "Expected end of text" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1740
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1741
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1742
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1743
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1744
        elif loc == len(instring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1745
            return loc+1, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1746
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1747
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1748
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1749
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1750
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1751
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1752
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1753
class ParseExpression(ParserElement):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1754
    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1755
    def __init__( self, exprs, savelist = False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1756
        super(ParseExpression,self).__init__(savelist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1757
        if isinstance( exprs, list ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1758
            self.exprs = exprs
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1759
        elif isinstance( exprs, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1760
            self.exprs = [ Literal( exprs ) ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1761
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1762
            self.exprs = [ exprs ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1763
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1764
    def __getitem__( self, i ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1765
        return self.exprs[i]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1766
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1767
    def append( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1768
        self.exprs.append( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1769
        self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1770
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1771
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1772
    def leaveWhitespace( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1773
        """Extends leaveWhitespace defined in base class, and also invokes leaveWhitespace on
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1774
           all contained expressions."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1775
        self.skipWhitespace = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1776
        self.exprs = [ e.copy() for e in self.exprs ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1777
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1778
            e.leaveWhitespace()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1779
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1780
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1781
    def ignore( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1782
        if isinstance( other, Suppress ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1783
            if other not in self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1784
                super( ParseExpression, self).ignore( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1785
                for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1786
                    e.ignore( self.ignoreExprs[-1] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1787
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1788
            super( ParseExpression, self).ignore( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1789
            for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1790
                e.ignore( self.ignoreExprs[-1] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1791
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1792
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1793
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1794
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1795
            return super(ParseExpression,self).__str__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1796
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1797
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1798
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1799
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1800
            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1801
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1802
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1803
    def streamline( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1804
        super(ParseExpression,self).streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1805
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1806
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1807
            e.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1808
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1809
        # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1810
        # but only if there are no parse actions or resultsNames on the nested And's
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1811
        # (likewise for Or's and MatchFirst's)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1812
        if ( len(self.exprs) == 2 ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1813
            other = self.exprs[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1814
            if ( isinstance( other, self.__class__ ) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1815
                  not(other.parseAction) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1816
                  other.resultsName is None and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1817
                  not other.debug ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1818
                self.exprs = other.exprs[:] + [ self.exprs[1] ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1819
                self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1820
                self.mayReturnEmpty |= other.mayReturnEmpty
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1821
                self.mayIndexError  |= other.mayIndexError
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1822
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1823
            other = self.exprs[-1]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1824
            if ( isinstance( other, self.__class__ ) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1825
                  not(other.parseAction) and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1826
                  other.resultsName is None and
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1827
                  not other.debug ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1828
                self.exprs = self.exprs[:-1] + other.exprs[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1829
                self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1830
                self.mayReturnEmpty |= other.mayReturnEmpty
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1831
                self.mayIndexError  |= other.mayIndexError
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1832
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1833
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1834
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1835
    def setResultsName( self, name, listAllMatches=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1836
        ret = super(ParseExpression,self).setResultsName(name,listAllMatches)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1837
        return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1838
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1839
    def validate( self, validateTrace=[] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1840
        tmp = validateTrace[:]+[self]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1841
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1842
            e.validate(tmp)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1843
        self.checkRecursion( [] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1844
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1845
class And(ParseExpression):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1846
    """Requires all given ParseExpressions to be found in the given order.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1847
       Expressions may be separated by whitespace.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1848
       May be constructed using the '+' operator.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1849
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1850
    def __init__( self, exprs, savelist = True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1851
        super(And,self).__init__(exprs, savelist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1852
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1853
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1854
            if not e.mayReturnEmpty:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1855
                self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1856
                break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1857
        self.setWhitespaceChars( exprs[0].whiteChars )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1858
        self.skipWhitespace = exprs[0].skipWhitespace
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1859
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1860
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1861
        # pass False as last arg to _parse for first element, since we already
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1862
        # pre-parsed the string as part of our And pre-parsing
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1863
        loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1864
        for e in self.exprs[1:]:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1865
            loc, exprtokens = e._parse( instring, loc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1866
            if exprtokens or exprtokens.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1867
                resultlist += exprtokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1868
        return loc, resultlist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1869
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1870
    def __iadd__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1871
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1872
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1873
        return self.append( other ) #And( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1874
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1875
    def checkRecursion( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1876
        subRecCheckList = parseElementList[:] + [ self ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1877
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1878
            e.checkRecursion( subRecCheckList )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1879
            if not e.mayReturnEmpty:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1880
                break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1881
                
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1882
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1883
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1884
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1885
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1886
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1887
            self.strRepr = "{" + " ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1888
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1889
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1890
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1891
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1892
class Or(ParseExpression):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1893
    """Requires that at least one ParseExpression is found.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1894
       If two expressions match, the expression that matches the longest string will be used.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1895
       May be constructed using the '^' operator.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1896
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1897
    def __init__( self, exprs, savelist = False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1898
        super(Or,self).__init__(exprs, savelist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1899
        self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1900
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1901
            if e.mayReturnEmpty:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1902
                self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1903
                break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1904
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1905
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1906
        maxExcLoc = -1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1907
        maxMatchLoc = -1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1908
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1909
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1910
                loc2 = e.tryParse( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1911
            except ParseException, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1912
                if err.loc > maxExcLoc:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1913
                    maxException = err
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1914
                    maxExcLoc = err.loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1915
            except IndexError, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1916
                if len(instring) > maxExcLoc:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1917
                    maxException = ParseException(instring,len(instring),e.errmsg,self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1918
                    maxExcLoc = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1919
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1920
                if loc2 > maxMatchLoc:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1921
                    maxMatchLoc = loc2
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1922
                    maxMatchExp = e
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1923
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1924
        if maxMatchLoc < 0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1925
            if self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1926
                raise maxException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1927
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1928
                raise ParseException(instring, loc, "no defined alternatives to match", self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1929
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1930
        return maxMatchExp._parse( instring, loc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1931
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1932
    def __ixor__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1933
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1934
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1935
        return self.append( other ) #Or( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1936
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1937
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1938
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1939
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1940
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1941
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1942
            self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1943
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1944
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1945
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1946
    def checkRecursion( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1947
        subRecCheckList = parseElementList[:] + [ self ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1948
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1949
            e.checkRecursion( subRecCheckList )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1950
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1951
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1952
class MatchFirst(ParseExpression):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1953
    """Requires that at least one ParseExpression is found.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1954
       If two expressions match, the first one listed is the one that will match.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1955
       May be constructed using the '|' operator.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1956
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1957
    def __init__( self, exprs, savelist = False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1958
        super(MatchFirst,self).__init__(exprs, savelist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1959
        if exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1960
            self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1961
            for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1962
                if e.mayReturnEmpty:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1963
                    self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1964
                    break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1965
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1966
            self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1967
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1968
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1969
        maxExcLoc = -1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1970
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1971
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1972
                ret = e._parse( instring, loc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1973
                return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1974
            except ParseException, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1975
                if err.loc > maxExcLoc:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1976
                    maxException = err
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1977
                    maxExcLoc = err.loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1978
            except IndexError, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1979
                if len(instring) > maxExcLoc:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1980
                    maxException = ParseException(instring,len(instring),e.errmsg,self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1981
                    maxExcLoc = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1982
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1983
        # only got here if no expression matched, raise exception for match that made it the furthest
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1984
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1985
            if self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1986
                raise maxException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1987
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1988
                raise ParseException(instring, loc, "no defined alternatives to match", self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1989
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1990
    def __ior__(self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1991
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1992
            other = Literal( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1993
        return self.append( other ) #MatchFirst( [ self, other ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1994
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1995
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1996
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1997
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1998
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  1999
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2000
            self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2001
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2002
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2003
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2004
    def checkRecursion( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2005
        subRecCheckList = parseElementList[:] + [ self ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2006
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2007
            e.checkRecursion( subRecCheckList )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2008
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2009
class Each(ParseExpression):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2010
    """Requires all given ParseExpressions to be found, but in any order.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2011
       Expressions may be separated by whitespace.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2012
       May be constructed using the '&' operator.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2013
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2014
    def __init__( self, exprs, savelist = True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2015
        super(Each,self).__init__(exprs, savelist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2016
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2017
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2018
            if not e.mayReturnEmpty:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2019
                self.mayReturnEmpty = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2020
                break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2021
        self.skipWhitespace = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2022
        self.optionals = [ e.expr for e in exprs if isinstance(e,Optional) ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2023
        self.multioptionals = [ e.expr for e in exprs if isinstance(e,ZeroOrMore) ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2024
        self.multirequired = [ e.expr for e in exprs if isinstance(e,OneOrMore) ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2025
        self.required = [ e for e in exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2026
        self.required += self.multirequired
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2027
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2028
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2029
        tmpLoc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2030
        tmpReqd = self.required[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2031
        tmpOpt  = self.optionals[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2032
        matchOrder = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2033
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2034
        keepMatching = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2035
        while keepMatching:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2036
            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2037
            failed = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2038
            for e in tmpExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2039
                try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2040
                    tmpLoc = e.tryParse( instring, tmpLoc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2041
                except ParseException:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2042
                    failed.append(e)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2043
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2044
                    matchOrder.append(e)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2045
                    if e in tmpReqd:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2046
                        tmpReqd.remove(e)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2047
                    elif e in tmpOpt:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2048
                        tmpOpt.remove(e)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2049
            if len(failed) == len(tmpExprs):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2050
                keepMatching = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2051
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2052
        if tmpReqd:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2053
            missing = ", ".join( [ _ustr(e) for e in tmpReqd ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2054
            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2055
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2056
        resultlist = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2057
        for e in matchOrder:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2058
            loc,results = e._parse(instring,loc,doActions)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2059
            resultlist.append(results)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2060
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2061
        finalResults = ParseResults([])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2062
        for r in resultlist:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2063
            dups = {}
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2064
            for k in r.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2065
                if k in finalResults.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2066
                    tmp = ParseResults(finalResults[k])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2067
                    tmp += ParseResults(r[k])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2068
                    dups[k] = tmp
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2069
            finalResults += ParseResults(r)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2070
            for k,v in dups.items():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2071
                finalResults[k] = v
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2072
        return loc, finalResults
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2073
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2074
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2075
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2076
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2077
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2078
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2079
            self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2080
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2081
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2082
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2083
    def checkRecursion( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2084
        subRecCheckList = parseElementList[:] + [ self ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2085
        for e in self.exprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2086
            e.checkRecursion( subRecCheckList )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2087
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2088
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2089
class ParseElementEnhance(ParserElement):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2090
    """Abstract subclass of ParserElement, for combining and post-processing parsed tokens."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2091
    def __init__( self, expr, savelist=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2092
        super(ParseElementEnhance,self).__init__(savelist)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2093
        if isinstance( expr, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2094
            expr = Literal(expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2095
        self.expr = expr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2096
        self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2097
        if expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2098
            self.mayIndexError = expr.mayIndexError
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2099
            self.setWhitespaceChars( expr.whiteChars )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2100
            self.skipWhitespace = expr.skipWhitespace
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2101
            self.saveAsList = expr.saveAsList
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2102
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2103
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2104
        if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2105
            return self.expr._parse( instring, loc, doActions, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2106
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2107
            raise ParseException("",loc,self.errmsg,self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2108
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2109
    def leaveWhitespace( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2110
        self.skipWhitespace = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2111
        self.expr = self.expr.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2112
        if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2113
            self.expr.leaveWhitespace()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2114
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2115
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2116
    def ignore( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2117
        if isinstance( other, Suppress ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2118
            if other not in self.ignoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2119
                super( ParseElementEnhance, self).ignore( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2120
                if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2121
                    self.expr.ignore( self.ignoreExprs[-1] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2122
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2123
            super( ParseElementEnhance, self).ignore( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2124
            if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2125
                self.expr.ignore( self.ignoreExprs[-1] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2126
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2127
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2128
    def streamline( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2129
        super(ParseElementEnhance,self).streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2130
        if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2131
            self.expr.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2132
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2133
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2134
    def checkRecursion( self, parseElementList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2135
        if self in parseElementList:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2136
            raise RecursiveGrammarException( parseElementList+[self] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2137
        subRecCheckList = parseElementList[:] + [ self ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2138
        if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2139
            self.expr.checkRecursion( subRecCheckList )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2140
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2141
    def validate( self, validateTrace=[] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2142
        tmp = validateTrace[:]+[self]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2143
        if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2144
            self.expr.validate(tmp)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2145
        self.checkRecursion( [] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2146
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2147
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2148
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2149
            return super(ParseElementEnhance,self).__str__()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2150
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2151
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2152
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2153
        if self.strRepr is None and self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2154
            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2155
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2156
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2157
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2158
class FollowedBy(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2159
    """Lookahead matching of the given parse expression.  FollowedBy
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2160
    does *not* advance the parsing position within the input string, it only 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2161
    verifies that the specified parse expression matches at the current 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2162
    position.  FollowedBy always returns a null token list."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2163
    def __init__( self, expr ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2164
        super(FollowedBy,self).__init__(expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2165
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2166
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2167
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2168
        self.expr.tryParse( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2169
        return loc, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2170
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2171
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2172
class NotAny(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2173
    """Lookahead to disallow matching with the given parse expression.  NotAny
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2174
    does *not* advance the parsing position within the input string, it only 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2175
    verifies that the specified parse expression does *not* match at the current 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2176
    position.  Also, NotAny does *not* skip over leading whitespace. NotAny 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2177
    always returns a null token list.  May be constructed using the '~' operator."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2178
    def __init__( self, expr ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2179
        super(NotAny,self).__init__(expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2180
        #~ self.leaveWhitespace()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2181
        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2182
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2183
        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2184
        self.myException = ParseException("",0,self.errmsg,self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2185
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2186
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2187
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2188
            self.expr.tryParse( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2189
        except (ParseException,IndexError):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2190
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2191
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2192
            #~ raise ParseException(instring, loc, self.errmsg )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2193
            exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2194
            exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2195
            exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2196
            raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2197
        return loc, []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2198
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2199
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2200
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2201
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2202
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2203
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2204
            self.strRepr = "~{" + _ustr(self.expr) + "}"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2205
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2206
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2207
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2208
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2209
class ZeroOrMore(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2210
    """Optional repetition of zero or more of the given expression."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2211
    def __init__( self, expr ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2212
        super(ZeroOrMore,self).__init__(expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2213
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2214
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2215
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2216
        tokens = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2217
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2218
            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2219
            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2220
            while 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2221
                if hasIgnoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2222
                    preloc = self.skipIgnorables( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2223
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2224
                    preloc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2225
                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2226
                if tmptokens or tmptokens.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2227
                    tokens += tmptokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2228
        except (ParseException,IndexError):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2229
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2230
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2231
        return loc, tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2232
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2233
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2234
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2235
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2236
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2237
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2238
            self.strRepr = "[" + _ustr(self.expr) + "]..."
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2239
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2240
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2241
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2242
    def setResultsName( self, name, listAllMatches=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2243
        ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2244
        ret.saveAsList = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2245
        return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2246
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2247
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2248
class OneOrMore(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2249
    """Repetition of one or more of the given expression."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2250
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2251
        # must be at least one
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2252
        loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2253
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2254
            hasIgnoreExprs = ( len(self.ignoreExprs) > 0 )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2255
            while 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2256
                if hasIgnoreExprs:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2257
                    preloc = self.skipIgnorables( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2258
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2259
                    preloc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2260
                loc, tmptokens = self.expr._parse( instring, preloc, doActions )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2261
                if tmptokens or tmptokens.keys():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2262
                    tokens += tmptokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2263
        except (ParseException,IndexError):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2264
            pass
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2265
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2266
        return loc, tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2267
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2268
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2269
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2270
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2271
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2272
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2273
            self.strRepr = "{" + _ustr(self.expr) + "}..."
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2274
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2275
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2276
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2277
    def setResultsName( self, name, listAllMatches=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2278
        ret = super(OneOrMore,self).setResultsName(name,listAllMatches)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2279
        ret.saveAsList = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2280
        return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2281
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2282
class _NullToken(object):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2283
    def __bool__(self):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2284
        return False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2285
    def __str__(self):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2286
        return ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2287
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2288
_optionalNotMatched = _NullToken()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2289
class Optional(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2290
    """Optional matching of the given expression.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2291
       A default return string can also be specified, if the optional expression
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2292
       is not found.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2293
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2294
    def __init__( self, exprs, default=_optionalNotMatched ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2295
        super(Optional,self).__init__( exprs, savelist=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2296
        self.defaultValue = default
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2297
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2298
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2299
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2300
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2301
            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2302
        except (ParseException,IndexError):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2303
            if self.defaultValue is not _optionalNotMatched:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2304
                tokens = [ self.defaultValue ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2305
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2306
                tokens = []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2307
        return loc, tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2308
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2309
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2310
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2311
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2312
            
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2313
        if self.strRepr is None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2314
            self.strRepr = "[" + _ustr(self.expr) + "]"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2315
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2316
        return self.strRepr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2317
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2318
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2319
class SkipTo(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2320
    """Token for skipping over all undefined text until the matched expression is found.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2321
       If include is set to true, the matched expression is also consumed.  The ignore
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2322
       argument is used to define grammars (typically quoted strings and comments) that 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2323
       might contain false matches.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2324
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2325
    def __init__( self, other, include=False, ignore=None ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2326
        super( SkipTo, self ).__init__( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2327
        if ignore is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2328
            self.expr = self.expr.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2329
            self.expr.ignore(ignore)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2330
        self.mayReturnEmpty = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2331
        self.mayIndexError = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2332
        self.includeMatch = include
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2333
        self.asList = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2334
        self.errmsg = "No match found for "+_ustr(self.expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2335
        self.myException = ParseException("",0,self.errmsg,self)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2336
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2337
    def parseImpl( self, instring, loc, doActions=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2338
        startLoc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2339
        instrlen = len(instring)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2340
        expr = self.expr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2341
        while loc <= instrlen:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2342
            try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2343
                loc = expr.skipIgnorables( instring, loc )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2344
                expr._parse( instring, loc, doActions=False, callPreParse=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2345
                if self.includeMatch:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2346
                    skipText = instring[startLoc:loc]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2347
                    loc,mat = expr._parse(instring,loc)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2348
                    if mat:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2349
                        return loc, [ skipText, mat ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2350
                    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2351
                        return loc, [ skipText ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2352
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2353
                    return loc, [ instring[startLoc:loc] ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2354
            except (ParseException,IndexError):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2355
                loc += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2356
        exc = self.myException
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2357
        exc.loc = loc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2358
        exc.pstr = instring
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2359
        raise exc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2360
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2361
class Forward(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2362
    """Forward declaration of an expression to be defined later -
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2363
       used for recursive grammars, such as algebraic infix notation.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2364
       When the expression is known, it is assigned to the Forward variable using the '<<' operator.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2365
       
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2366
       Note: take care when assigning to Forward not to overlook precedence of operators.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2367
       Specifically, '|' has a lower precedence than '<<', so that::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2368
          fwdExpr << a | b | c
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2369
       will actually be evaluated as::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2370
          (fwdExpr << a) | b | c
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2371
       thereby leaving b and c out as parseable alternatives.  It is recommended that you
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2372
       explicitly group the values inserted into the Forward::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2373
          fwdExpr << (a | b | c)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2374
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2375
    def __init__( self, other=None ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2376
        super(Forward,self).__init__( other, savelist=False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2377
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2378
    def __lshift__( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2379
        if isinstance( other, basestring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2380
            other = Literal(other)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2381
        self.expr = other
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2382
        self.mayReturnEmpty = other.mayReturnEmpty
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2383
        self.strRepr = None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2384
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2385
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2386
    def leaveWhitespace( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2387
        self.skipWhitespace = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2388
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2389
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2390
    def streamline( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2391
        if not self.streamlined:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2392
            self.streamlined = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2393
            if self.expr is not None: 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2394
                self.expr.streamline()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2395
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2396
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2397
    def validate( self, validateTrace=[] ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2398
        if self not in validateTrace:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2399
            tmp = validateTrace[:]+[self]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2400
            if self.expr is not None: 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2401
                self.expr.validate(tmp)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2402
        self.checkRecursion([])        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2403
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2404
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2405
        if hasattr(self,"name"):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2406
            return self.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2407
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2408
        self.__class__ = _ForwardNoRecurse
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2409
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2410
            if self.expr is not None: 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2411
                retString = _ustr(self.expr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2412
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2413
                retString = "None"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2414
        finally:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2415
            self.__class__ = Forward
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2416
        return "Forward: "+retString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2417
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2418
    def copy(self):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2419
        if self.expr is not None:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2420
            return super(Forward,self).copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2421
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2422
            ret = Forward()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2423
            ret << self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2424
            return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2425
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2426
class _ForwardNoRecurse(Forward):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2427
    def __str__( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2428
        return "..."
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2429
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2430
class TokenConverter(ParseElementEnhance):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2431
    """Abstract subclass of ParseExpression, for converting parsed results."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2432
    def __init__( self, expr, savelist=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2433
        super(TokenConverter,self).__init__( expr )#, savelist )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2434
        self.saveAsList = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2435
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2436
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2437
class Upcase(TokenConverter):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2438
    """Converter to upper case all matching tokens."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2439
    def __init__(self, *args):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2440
        super(Upcase,self).__init__(*args)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2441
        warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead", 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2442
                       DeprecationWarning,stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2443
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2444
    def postParse( self, instring, loc, tokenlist ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2445
        return map( string.upper, tokenlist )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2446
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2447
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2448
class Combine(TokenConverter):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2449
    """Converter to concatenate all matching tokens to a single string.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2450
       By default, the matching patterns must also be contiguous in the input string;
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2451
       this can be disabled by specifying 'adjacent=False' in the constructor.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2452
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2453
    def __init__( self, expr, joinString="", adjacent=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2454
        super(Combine,self).__init__( expr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2455
        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2456
        if adjacent:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2457
            self.leaveWhitespace()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2458
        self.adjacent = adjacent
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2459
        self.skipWhitespace = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2460
        self.joinString = joinString
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2461
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2462
    def ignore( self, other ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2463
        if self.adjacent:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2464
            ParserElement.ignore(self, other)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2465
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2466
            super( Combine, self).ignore( other )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2467
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2468
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2469
    def postParse( self, instring, loc, tokenlist ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2470
        retToks = tokenlist.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2471
        del retToks[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2472
        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2473
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2474
        if self.resultsName and len(retToks.keys())>0:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2475
            return [ retToks ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2476
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2477
            return retToks
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2478
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2479
class Group(TokenConverter):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2480
    """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2481
    def __init__( self, expr ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2482
        super(Group,self).__init__( expr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2483
        self.saveAsList = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2484
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2485
    def postParse( self, instring, loc, tokenlist ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2486
        return [ tokenlist ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2487
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2488
class Dict(TokenConverter):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2489
    """Converter to return a repetitive expression as a list, but also as a dictionary.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2490
       Each element can also be referenced using the first token in the expression as its key.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2491
       Useful for tabular report scraping when the first column can be used as a item key.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2492
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2493
    def __init__( self, exprs ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2494
        super(Dict,self).__init__( exprs )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2495
        self.saveAsList = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2496
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2497
    def postParse( self, instring, loc, tokenlist ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2498
        for i,tok in enumerate(tokenlist):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2499
            ikey = _ustr(tok[0]).strip()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2500
            if len(tok)==1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2501
                tokenlist[ikey] = ("",i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2502
            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2503
                tokenlist[ikey] = (tok[1],i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2504
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2505
                dictvalue = tok.copy() #ParseResults(i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2506
                del dictvalue[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2507
                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2508
                    tokenlist[ikey] = (dictvalue,i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2509
                else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2510
                    tokenlist[ikey] = (dictvalue[0],i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2511
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2512
        if self.resultsName:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2513
            return [ tokenlist ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2514
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2515
            return tokenlist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2516
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2517
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2518
class Suppress(TokenConverter):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2519
    """Converter for ignoring the results of a parsed expression."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2520
    def postParse( self, instring, loc, tokenlist ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2521
        return []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2522
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2523
    def suppress( self ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2524
        return self
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2525
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2526
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2527
class OnlyOnce(object):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2528
    """Wrapper for parse actions, to ensure they are only called once."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2529
    def __init__(self, methodCall):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2530
        self.callable = ParserElement.normalizeParseActionArgs(methodCall)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2531
        self.called = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2532
    def __call__(self,s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2533
        if not self.called:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2534
            results = self.callable(s,l,t)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2535
            self.called = True
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2536
            return results
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2537
        raise ParseException(s,l,"")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2538
    def reset():
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2539
        self.called = False
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2540
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2541
def traceParseAction(f):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2542
    """Decorator for debugging parse actions."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2543
    f = ParserElement.normalizeParseActionArgs(f)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2544
    def z(*paArgs):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2545
        thisFunc = f.func_name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2546
        s,l,t = paArgs[-3:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2547
        if len(paArgs)>3:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2548
            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2549
        sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2550
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2551
            ret = f(*paArgs)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2552
        except Exception, exc:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2553
            sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2554
            raise
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2555
        sys.stderr.write( "<<leaving %s (ret: %s)\n" % (thisFunc,ret) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2556
        return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2557
    return z
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2558
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2559
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2560
# global helpers
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2561
#
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2562
def delimitedList( expr, delim=",", combine=False ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2563
    """Helper to define a delimited list of expressions - the delimiter defaults to ','.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2564
       By default, the list elements and delimiters can have intervening whitespace, and 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2565
       comments, but this can be overridden by passing 'combine=True' in the constructor.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2566
       If combine is set to True, the matching tokens are returned as a single token
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2567
       string, with the delimiters included; otherwise, the matching tokens are returned
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2568
       as a list of tokens, with the delimiters suppressed.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2569
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2570
    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2571
    if combine:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2572
        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2573
    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2574
        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2575
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2576
def countedArray( expr ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2577
    """Helper to define a counted list of expressions.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2578
       This helper defines a pattern of the form::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2579
           integer expr expr expr...
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2580
       where the leading integer tells how many expr expressions follow.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2581
       The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2582
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2583
    arrayExpr = Forward()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2584
    def countFieldParseAction(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2585
        n = int(t[0])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2586
        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2587
        return []
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2588
    return ( Word(nums).setParseAction(countFieldParseAction) + arrayExpr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2589
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2590
def _flatten(L):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2591
    if type(L) is not list: return [L]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2592
    if L == []: return L
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2593
    return _flatten(L[0]) + _flatten(L[1:])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2594
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2595
def matchPreviousLiteral(expr):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2596
    """Helper to define an expression that is indirectly defined from
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2597
       the tokens matched in a previous expression, that is, it looks
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2598
       for a 'repeat' of a previous expression.  For example::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2599
           first = Word(nums)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2600
           second = matchPreviousLiteral(first)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2601
           matchExpr = first + ":" + second
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2602
       will match "1:1", but not "1:2".  Because this matches a 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2603
       previous literal, will also match the leading "1:1" in "1:10".  
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2604
       If this is not desired, use matchPreviousExpr.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2605
       Do *not* use with packrat parsing enabled.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2606
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2607
    rep = Forward()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2608
    def copyTokenToRepeater(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2609
        if t:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2610
            if len(t) == 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2611
                rep << t[0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2612
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2613
                # flatten t tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2614
                tflat = _flatten(t.asList())
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2615
                rep << And( [ Literal(tt) for tt in tflat ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2616
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2617
            rep << Empty()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2618
    expr.addParseAction(copyTokenToRepeater)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2619
    return rep
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2620
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2621
def matchPreviousExpr(expr):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2622
    """Helper to define an expression that is indirectly defined from
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2623
       the tokens matched in a previous expression, that is, it looks
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2624
       for a 'repeat' of a previous expression.  For example::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2625
           first = Word(nums)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2626
           second = matchPreviousExpr(first)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2627
           matchExpr = first + ":" + second
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2628
       will match "1:1", but not "1:2".  Because this matches by
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2629
       expressions, will *not* match the leading "1:1" in "1:10";
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2630
       the expressions are evaluated first, and then compared, so
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2631
       "1" is compared with "10".
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2632
       Do *not* use with packrat parsing enabled.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2633
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2634
    rep = Forward()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2635
    e2 = expr.copy()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2636
    rep << e2
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2637
    def copyTokenToRepeater(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2638
        matchTokens = _flatten(t.asList())
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2639
        def mustMatchTheseTokens(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2640
            theseTokens = _flatten(t.asList())
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2641
            if  theseTokens != matchTokens:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2642
                raise ParseException("",0,"")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2643
        rep.setParseAction( mustMatchTheseTokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2644
    expr.addParseAction(copyTokenToRepeater)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2645
    return rep
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2646
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2647
def _escapeRegexRangeChars(s):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2648
    #~  escape these chars: ^-]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2649
    for c in r"\^-]":
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2650
        s = s.replace(c,"\\"+c)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2651
    s = s.replace("\n",r"\n")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2652
    s = s.replace("\t",r"\t")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2653
    return _ustr(s)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2654
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2655
def oneOf( strs, caseless=False, useRegex=True ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2656
    """Helper to quickly define a set of alternative Literals, and makes sure to do 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2657
       longest-first testing when there is a conflict, regardless of the input order, 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2658
       but returns a MatchFirst for best performance.  
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2659
       
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2660
       Parameters:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2661
        - strs - a string of space-delimited literals, or a list of string literals
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2662
        - caseless - (default=False) - treat all literals as caseless
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2663
        - useRegex - (default=True) - as an optimization, will generate a Regex
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2664
          object; otherwise, will generate a MatchFirst object (if caseless=True, or
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2665
          if creating a Regex raises an exception)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2666
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2667
    if caseless:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2668
        isequal = ( lambda a,b: a.upper() == b.upper() )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2669
        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2670
        parseElementClass = CaselessLiteral
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2671
    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2672
        isequal = ( lambda a,b: a == b )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2673
        masks = ( lambda a,b: b.startswith(a) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2674
        parseElementClass = Literal
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2675
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2676
    if isinstance(strs,(list,tuple)):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2677
        symbols = strs[:]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2678
    elif isinstance(strs,basestring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2679
        symbols = strs.split()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2680
    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2681
        warnings.warn("Invalid argument to oneOf, expected string or list",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2682
                SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2683
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2684
    i = 0
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2685
    while i < len(symbols)-1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2686
        cur = symbols[i]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2687
        for j,other in enumerate(symbols[i+1:]):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2688
            if ( isequal(other, cur) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2689
                del symbols[i+j+1]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2690
                break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2691
            elif ( masks(cur, other) ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2692
                del symbols[i+j+1]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2693
                symbols.insert(i,other)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2694
                cur = other
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2695
                break
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2696
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2697
            i += 1
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2698
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2699
    if not caseless and useRegex:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2700
        #~ print strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2701
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2702
            if len(symbols)==len("".join(symbols)):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2703
                return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2704
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2705
                return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2706
        except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2707
            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2708
                    SyntaxWarning, stacklevel=2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2709
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2710
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2711
    # last resort, just use MatchFirst
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2712
    return MatchFirst( [ parseElementClass(sym) for sym in symbols ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2713
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2714
def dictOf( key, value ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2715
    """Helper to easily and clearly define a dictionary by specifying the respective patterns
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2716
       for the key and value.  Takes care of defining the Dict, ZeroOrMore, and Group tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2717
       in the proper order.  The key pattern can include delimiting markers or punctuation,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2718
       as long as they are suppressed, thereby leaving the significant key text.  The value
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2719
       pattern can include named results, so that the Dict results can include named token 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2720
       fields.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2721
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2722
    return Dict( ZeroOrMore( Group ( key + value ) ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2723
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2724
_bslash = "\\"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2725
printables = "".join( [ c for c in string.printable if c not in string.whitespace ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2726
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2727
# convenience constants for positional expressions
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2728
empty       = Empty().setName("empty")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2729
lineStart   = LineStart().setName("lineStart")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2730
lineEnd     = LineEnd().setName("lineEnd")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2731
stringStart = StringStart().setName("stringStart")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2732
stringEnd   = StringEnd().setName("stringEnd")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2733
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2734
_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2735
_printables_less_backslash = "".join([ c for c in printables if c not in  r"\]" ])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2736
_escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16)))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2737
_escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8)))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2738
_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2739
_charRange = Group(_singleChar + Suppress("-") + _singleChar)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2740
_reBracketExpr = "[" + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2741
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2742
_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2743
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2744
def srange(s):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2745
    r"""Helper to easily define string ranges for use in Word construction.  Borrows
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2746
       syntax from regexp '[]' string range definitions::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2747
          srange("[0-9]")   -> "0123456789"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2748
          srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2749
          srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2750
       The input string must be enclosed in []'s, and the returned string is the expanded 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2751
       character set joined into a single string.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2752
       The values enclosed in the []'s may be::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2753
          a single character
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2754
          an escaped character with a leading backslash (such as \- or \])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2755
          an escaped hex character with a leading '\0x' (\0x21, which is a '!' character)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2756
          an escaped octal character with a leading '\0' (\041, which is a '!' character)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2757
          a range of any of the above, separated by a dash ('a-z', etc.)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2758
          any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2759
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2760
    try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2761
        return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body])
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2762
    except:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2763
        return ""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2764
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2765
def replaceWith(replStr):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2766
    """Helper method for common parse actions that simply return a literal value.  Especially 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2767
       useful when used with transformString().
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2768
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2769
    def _replFunc(*args):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2770
        return [replStr]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2771
    return _replFunc
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2772
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2773
def removeQuotes(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2774
    """Helper parse action for removing quotation marks from parsed quoted strings.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2775
       To use, add this parse action to quoted string using::
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2776
         quotedString.setParseAction( removeQuotes )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2777
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2778
    return t[0][1:-1]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2779
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2780
def upcaseTokens(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2781
    """Helper parse action to convert tokens to upper case."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2782
    return [ str(tt).upper() for tt in t ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2783
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2784
def downcaseTokens(s,l,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2785
    """Helper parse action to convert tokens to lower case."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2786
    return [ str(tt).lower() for tt in t ]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2787
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2788
def keepOriginalText(s,startLoc,t):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2789
    import inspect
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2790
    """Helper parse action to preserve original parsed text,
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2791
       overriding any nested parse actions."""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2792
    f = inspect.stack()[1][0]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2793
    try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2794
        endloc = f.f_locals["loc"]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2795
    finally:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2796
        del f
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2797
    return s[startLoc:endloc]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2798
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2799
def _makeTags(tagStr, xml):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2800
    """Internal helper to construct opening and closing tag expressions, given a tag name"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2801
    if isinstance(tagStr,basestring):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2802
        resname = tagStr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2803
        tagStr = Keyword(tagStr, caseless=not xml)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2804
    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2805
        resname = tagStr.name
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2806
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2807
    tagAttrName = Word(alphas,alphanums+"_-")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2808
    if (xml):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2809
        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2810
        openTag = Suppress("<") + tagStr + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2811
                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2812
                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2813
    else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2814
        printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2815
        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2816
        openTag = Suppress("<") + tagStr + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2817
                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2818
                Suppress("=") + tagAttrValue ))) + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2819
                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2820
    closeTag = Combine("</" + tagStr + ">")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2821
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2822
    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2823
    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % tagStr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2824
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2825
    return openTag, closeTag
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2826
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2827
def makeHTMLTags(tagStr):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2828
    """Helper to construct opening and closing tag expressions for HTML, given a tag name"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2829
    return _makeTags( tagStr, False )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2830
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2831
def makeXMLTags(tagStr):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2832
    """Helper to construct opening and closing tag expressions for XML, given a tag name"""
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2833
    return _makeTags( tagStr, True )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2834
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2835
opAssoc = _Constants()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2836
opAssoc.LEFT = object()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2837
opAssoc.RIGHT = object()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2838
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2839
def operatorPrecedence( baseExpr, opList ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2840
    """Helper method for constructing grammars of expressions made up of 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2841
       operators working in a precedence hierarchy.  Operators may be unary or
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2842
       binary, left- or right-associative.  Parse actions can also be attached
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2843
       to operator expressions.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2844
        
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2845
       Parameters:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2846
        - baseExpr - expression representing the most basic element for the nested 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2847
        - opList - list of tuples, one for each operator precedence level in the expression grammar; each tuple is of the form
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2848
          (opExpr, numTerms, rightLeftAssoc, parseAction), where:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2849
           - opExpr is the pyparsing expression for the operator;
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2850
              may also be a string, which will be converted to a Literal
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2851
           - numTerms is the number of terms for this operator (must
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2852
              be 1 or 2)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2853
           - rightLeftAssoc is the indicator whether the operator is
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2854
              right or left associative, using the pyparsing-defined
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2855
              constants opAssoc.RIGHT and opAssoc.LEFT.
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2856
           - parseAction is the parse action to be associated with 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2857
              expressions matching this operator expression (the
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2858
              parse action tuple member may be omitted)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2859
    """
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2860
    ret = Forward()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2861
    lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2862
    for i,operDef in enumerate(opList):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2863
        opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2864
        thisExpr = Forward().setName("expr%d" % i)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2865
        if rightLeftAssoc == opAssoc.LEFT:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2866
            if arity == 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2867
                matchExpr = Group( lastExpr + opExpr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2868
            elif arity == 2:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2869
                matchExpr = Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2870
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2871
                raise ValueError, "operator must be unary (1) or binary (2)"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2872
        elif rightLeftAssoc == opAssoc.RIGHT:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2873
            if arity == 1:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2874
                # try to avoid LR with this extra test
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2875
                if not isinstance(opExpr, Optional):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2876
                    opExpr = Optional(opExpr)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2877
                matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2878
            elif arity == 2:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2879
                matchExpr = Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2880
            else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2881
                raise ValueError, "operator must be unary (1) or binary (2)"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2882
        else:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2883
            raise ValueError, "operator must indicate right or left associativity"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2884
        if pa:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2885
            matchExpr.setParseAction( pa )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2886
        thisExpr << ( matchExpr | lastExpr )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2887
        lastExpr = thisExpr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2888
    ret << lastExpr
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2889
    return ret
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2890
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2891
alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2892
punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2893
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2894
dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\.))*"').setName("string enclosed in double quotes")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2895
sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\.))*'").setName("string enclosed in single quotes")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2896
quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\.))*')''').setName("quotedString using single or double quotes")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2897
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2898
anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_"))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2899
commonHTMLEntity = Combine("&" + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2900
_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),"><& '"))
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2901
replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2902
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2903
# it's easy to get these comment structures wrong - they're very common, so may as well make them available
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2904
cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2905
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2906
htmlComment = Regex(r"<!--[\s\S]*?-->")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2907
restOfLine = Regex(r".*").leaveWhitespace()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2908
dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2909
cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?<!\\)|\Z))").setName("C++ style comment")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2910
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2911
javaStyleComment = cppStyleComment
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2912
pythonStyleComment = Regex(r"#.*").setName("Python style comment")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2913
_noncomma = "".join( [ c for c in printables if c != "," ] )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2914
_commasepitem = Combine(OneOrMore(Word(_noncomma) + 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2915
                                  Optional( Word(" \t") + 
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2916
                                            ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2917
commaSeparatedList = delimitedList( Optional( quotedString | _commasepitem, default="") ).setName("commaSeparatedList")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2918
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2919
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2920
if __name__ == "__main__":
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2921
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2922
    def test( teststring ):
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2923
        print teststring,"->",
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2924
        try:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2925
            tokens = simpleSQL.parseString( teststring )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2926
            tokenlist = tokens.asList()
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2927
            print tokenlist
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2928
            print "tokens = ",        tokens
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2929
            print "tokens.columns =", tokens.columns
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2930
            print "tokens.tables =",  tokens.tables
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2931
            print tokens.asXML("SQL",True)
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2932
        except ParseException, err:
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2933
            print err.line
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2934
            print " "*(err.column-1) + "^"
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2935
            print err
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2936
        print
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2937
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2938
    selectToken    = CaselessLiteral( "select" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2939
    fromToken      = CaselessLiteral( "from" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2940
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2941
    ident          = Word( alphas, alphanums + "_$" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2942
    columnName     = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2943
    columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2944
    tableName      = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2945
    tableNameList  = Group( delimitedList( tableName ) )#.setName("tables")
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2946
    simpleSQL      = ( selectToken + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2947
                     ( '*' | columnNameList ).setResultsName( "columns" ) + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2948
                     fromToken + \
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2949
                     tableNameList.setResultsName( "tables" ) )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2950
    
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2951
    test( "SELECT * from XYZZY, ABC" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2952
    test( "select * from SYS.XYZZY" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2953
    test( "Select A from Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2954
    test( "Select AA,BB,CC from Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2955
    test( "Select A, B, C from Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2956
    test( "Select A, B, C from Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2957
    test( "Xelect A, B, C from Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2958
    test( "Select A, B, C frox Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2959
    test( "Select" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2960
    test( "Select ^^^ frox Sys.dual" )
e1eecf4d390d Team sf branch.
tnmurphy@4GBL06592.nokia.com
parents: 0
diff changeset
  2961
    test( "Select A, B, C from Sys.dual, Table2   " )