1 # -*- coding: iso-8859-1 -*-
4 # A quick made parser for mail.filter configuration file.
6 # The parser could be interesting for some other uses though.
12 #-----------------------------------------------------------------------------
14 class ParserError( Exception ) : pass
18 def __init__( self , tokens , text ) :
20 self.tokenMatches = {}
21 for k , v in tokens.items() :
22 if type( v ) in types.StringTypes :
24 self.tokenMatches[ k ] = v
27 self.tokensToIgnore = ()
31 def ignore( self , *tokens ) :
33 self.tokensToIgnore = tokens
35 def peek( self , *set ) :
39 set = self.tokenMatches.keys()
40 for tokenName in set :
41 tokenMatch = self.tokenMatches.get( tokenName )
42 if not tokenMatch : continue
43 m = tokenMatch.match( self.text , self.pos )
46 tokens.append( ( tokenName , tk ) )
47 tokens.sort( lambda a , b : cmp( len( a[ 1 ] ) , len( b[ 1 ] ) ) )
50 def advance( self , n ) :
52 if type( n ) in types.StringTypes :
54 p = self.text.rfind( '\n' , self.pos , self.pos + n )
58 self.x = self.pos + n - p
59 self.y += self.text.count( '\n' , self.pos , self.pos + n )
62 def snext( self , *set ) :
64 set += self.tokensToIgnore
71 self.advance( r[ 1 ] )
72 if r[ 0 ] not in self.tokensToIgnore :
76 def next( self , *set ) :
78 r = self.snext( *set )
82 misc = 'found %r but ' % r[ 0 ][ 1 ]
85 raise ParserError( '%s, %sexpected one of the following tokens: %r'
86 % ( self.getPos() , misc , list( set ) ) )
91 return 'at line %d, column %d' % ( self.y , self.x )
95 lineStart = self.text.rfind( '\n' , 0 , self.pos + 1 ) + 1
96 lineEnd = self.text.find( '\n' , self.pos + 1 )
98 lineEnd = len( self.text )
99 prefix = 'line %s: ' % self.y
101 r += prefix + self.text[ lineStart : lineEnd ].replace( '\t' , ' ' ) + '\n'
102 r += prefix + ' ' * ( self.pos - lineStart ) + '^' + '\n'