1"""Dispatch-processor API
2
3This is a post-processing processor API based on dispatching
4each element of a result tree in a top-down recursive call
5structure.  It is the API used by the SimpleParseGrammar Parser,
6and likely will be the default processor for SimpleParse.
7"""
8from simpleparse.processor import Processor
9
10class DispatchProcessor(Processor):
11    """Dispatch results-tree in a top-down recursive pattern with
12    attribute lookup to determine production -> method correspondence.
13
14    To use the class, subclass it, then define methods for
15    processing each production.  The methods should take this form:
16        def production_name( self, (tag, left, right, children), buffer):
17            pass
18    Where children may be either a list, or None, and buffer is the
19    entire buffer being parsed.
20    """
21    def __call__( self, value, buffer ):
22        """Process the results of the parsing run over buffer
23
24        Value can either be: (success, tags, next) for a top-level
25        production, or (tag, left, right, children) for a non-top
26        production.
27        """
28        if len( value ) == 3:
29            # is a top-level production
30            success, tags, next = value
31            if success:
32                result = dispatchList( self, tags, buffer )
33                return success, result, next
34            else:
35                return success, tags, next
36        else:
37            # is a 4-item result tuple/tree
38            return dispatch( self, value, buffer )
39
40
41def dispatch( source, tag, buffer ):
42    """Dispatch on source for tag with buffer
43
44    Find the attribute or key tag[0] of source,
45    then call it with (tag, buffer)
46    """
47    try:
48        function = getattr (source, tag[0])
49    except AttributeError:
50        try:
51            function = source[tag[0]]
52        except:
53            raise AttributeError( '''No processing function for tag "%s" in object %s! Check the parser definition!'''%(tag[0], repr(source)))
54    return function( tag, buffer )
55
56def dispatchList( source, taglist, buffer ):
57    """Dispatch on source for each tag in taglist with buffer"""
58    if taglist:
59        return list(map( dispatch, [source]*len(taglist), taglist, [buffer]*len(taglist)))
60    else:
61        return []
62
63def multiMap( taglist, source=None, buffer=None ):
64    """Convert a taglist to a mapping from tag-object:[list-of-tags]
65
66    For instance, if you have items of 3 different types, in any order,
67    you can retrieve them all sorted by type with multimap( childlist)
68    then access them by tagobject key.
69    """
70    set = {}
71    if not taglist:
72        return set
73    for tag in taglist:
74        key = tag[0]
75        if source and buffer:
76            tag = dispatch( source, tag, buffer )
77        set.setdefault(key,[]).append( tag )
78    return set
79def singleMap( taglist, source=None, buffer=None ):
80    """Convert a taglist to a mapping from tag-object:tag, overwritting early with late tags"""
81    set = {}
82    if not taglist:
83        return set
84    for tag in taglist:
85        key = tag[0]
86        if source and buffer:
87            tag = dispatch( source, tag, buffer )
88        set[key] = tag
89    return set
90
91def getString(info, buffer):
92    """Return the string value of the tag passed"""
93    (tag, left, right, sublist) = info
94    return buffer[ left:right ]
95
96try:
97    from simpleparse.stt.TextTools import countlines
98except ImportError:
99    def lines( start=None, end=None, buffer=None ):
100        """Return line number in file at character index (string.count version)"""
101        return buffer.count('\n', start or 0, end or len(buffer))
102else:
103    def lines( start=None, end=None, buffer=None ):
104        """Return line number in file at character index (mx.TextTools version)"""
105        return countlines (buffer[start or 0:end or len(buffer)])
106
107
108