Fixed / overloading when enabling true division.
[tx] / patternparser.py
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3
4 # XSLT Pattern parser
5 # Copyright (C) 2005  Frédéric Jolliton <frederic@jolliton.com>
6
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21 import re
22
23 from xpath_misc import lispy
24 from parser import *
25
26 first = lambda l : l[ 0 ]
27 second = lambda l : l[ 1 ]
28
29 def tag( name ) :
30
31         return lambda o : ( name , o )
32
33 def constantly( item ) :
34
35         return lambda o : item
36
37 # ----[ XPath ]----
38
39 from xpathparser import nodeTest, predicateList, varRef, literal, stringLiteral
40
41 # ----[ XSLT pattern ]----
42
43 # [8] KeyValue
44 keyValue = \
45         Either( literal , varRef )
46
47 # [7] IdValue
48 idValue = \
49         Either( stringLiteral , varRef )
50
51 # [6] IdKeyPattern
52 def ptId( e ) :
53         return ( 'call' , 'ext:filter-by-id' , ( 'path' , e[ 2 ] ) )
54 def ptKey( e ) :
55         return ( 'key' , e[ 2 ] , e[ 4 ] )
56 idKeyPattern = \
57         Either( Sequence( 'id' , '(' , idValue , ')' ).call( ptId ) )
58                         #Sequence( 'key' , '(' , stringLiteral , ',' , keyValue , ')' ).call( ptKey ) )
59
60 # [5] PatternAxis
61 patternAxis = \
62         Either( Sequence( 'child' , Literal( '::' ).ignore() ).call( first ) ,
63                         Sequence( 'attribute' , Literal( '::' ).ignore() ).call( first ) ,
64                         '@' )
65
66 # [4] PatternStep
67 def ptPatternStep( e ) :
68         #print '>>' , e
69         if e[ 0 ] :
70                 axis = e[ 0 ][ 0 ]
71                 if axis == 'child' :
72                         if e[ 1 ][ 0 ] == 'name' :
73                                 s = ( 'implicit-child' , ( 'element' , e[ 1 ][ 1 ] ) )
74                         else :
75                                 s = ( axis , e[ 1 ] )
76                 elif axis in ( 'attribute' , '@' ) :
77                         if e[ 1 ][ 0 ] == 'name' :
78                                 s = ( 'attribute' , ( 'attribute' , e[ 1 ][ 1 ] ) )
79                         else :
80                                 s = ( 'attribute' , e[ 1 ] )
81                 else :
82                         raise NotReached
83         else :
84                 if e[ 1 ][ 0 ] == 'name' :
85                         s = ( 'implicit-child' , ( 'element' , e[ 1 ][ 1 ] ) )
86                 else :
87                         if e[ 1 ][ 0 ] == 'attribute' :
88                                 axis = 'attribute'
89                         else :
90                                 axis = 'implicit-child'
91                         s = ( axis , e[ 1 ] )
92         #print '<<' , s
93         if e[ 2 ] :
94                 return ( 'predicates' , s ) + tuple( e[ 2 ] )
95         else :
96                 return s
97 patternStep = \
98         Sequence( Optional( patternAxis ) ,
99                           nodeTest ,
100                           predicateList ).call( ptPatternStep )
101
102 # [3] RelativePathPattern
103 def ptRelativePathPattern( e ) :
104         result = [ e[ 0 ] ]
105         e = e[ 1 : ]
106         while e :
107                 if e[ 0 ] == '/' :
108                         pass
109                 elif e[ 0 ] == '//' :
110                         result.append( '//' )
111                 else :
112                         raise NotReached
113                 result.append( e[ 1 ] )
114                 e = e[ 2 : ]
115         return ( 'path' , ) + tuple( result )
116 relativePathPattern = \
117         List( patternStep , Regex( '//|/' ) ).call( ptRelativePathPattern )
118
119 # [2] PathPattern
120 def ptPathPatternFromRoot( e ) :
121         if not e[ 1 ] :
122                 return ( 'path' , '/' )
123         else :
124                 return ( 'path' , '/' ) + e[ 1 ][ 0 ][ 1 : ]
125 def ptPathPatternDescendant( e ) :
126         return ( 'path' , '//' ) + e[ 1 ][ 1 : ]
127 def ptPathPatternId( e ) :
128         if not e[ 1 ] :
129                 return ( 'path' , e[ 0 ] )
130         else :
131                 p = e[ 1 ][ 0 ]
132                 if p[ 0 ] == '/' :
133                         return ( 'path' , e[ 0 ] ) + tuple( p[ 1 ][ 1 : ] )
134                 else :
135                         return ( 'path' , e[ 0 ] , p[ 0 ] ) + tuple( p[ 1 ][ 1 : ] )
136 pathPattern = \
137         Either( relativePathPattern ,
138                         Sequence( '/' , Optional( relativePathPattern ) ).call( ptPathPatternFromRoot ) ,
139                         Sequence( '//' , relativePathPattern ).call( ptPathPatternDescendant ) ,
140                         Sequence( idKeyPattern ,
141                                           Optional( Sequence( Either( '/' , '//' ) ,
142                                                                                   relativePathPattern ) ) ).call( ptPathPatternId ) )
143
144 # [1] Pattern
145 def ptPattern( e ) :
146         if len( e ) > 1 :
147                 e = ( 'either' , ) + tuple( e )
148         else :
149                 e = e[ 0 ]
150         return ( 'pattern' , e )
151 pattern = \
152         List( pathPattern , Literal( '|' ).ignore() ).call( ptPattern )
153
154 parser = pattern.parse
155
156 # Local Variables:
157 # tab-width: 4
158 # python-indent: 4
159 # End: