2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """ Hierarchical property system for IDL AST """
10 from idl_log
import ErrOut
, InfoOut
, WarnOut
11 from idl_option
import GetOption
, Option
, ParseOptions
16 # A property node is a hierarchically aware system for mapping
17 # keys to values, such that a local dictionary is search first,
18 # followed by parent dictionaries in order.
20 class IDLPropertyNode(object):
23 self
.property_map
= {}
26 name
= self
.GetProperty('NAME', 'Unknown')
27 parents
= [parent
.GetProperty('NAME', '???') for parent
in self
.parents
]
28 ErrOut
.Log('%s [%s] : %s' % (name
, ' '.join(parents
), msg
))
30 def AddParent(self
, parent
):
32 self
.parents
.append(parent
)
34 def SetProperty(self
, name
, val
):
35 self
.property_map
[name
] = val
37 def _GetProperty_(self
, name
):
38 # Check locally for the property, and return it if found.
39 prop
= self
.property_map
.get(name
, None)
40 if prop
is not None: return prop
41 # If not, seach parents in order
42 for parent
in self
.parents
:
43 prop
= parent
.GetProperty(name
)
44 if prop
is not None: return prop
45 # Otherwise, it can not be found.
48 def GetProperty(self
, name
, default
=None):
49 prop
= self
._GetProperty
_(name
)
55 def GetPropertyLocal(self
, name
, default
=None):
56 # Search for the property, but only locally, returning the
57 # default if not found.
58 prop
= self
.property_map
.get(name
, default
)
61 # Regular expression to parse property keys in a string such that a string
62 # "My string $NAME$" will find the key "NAME".
63 regex_var
= re
.compile('(?P<src>[^\\$]+)|(?P<key>\\$\\w+\\$)')
65 def GetPropertyList(self
):
66 return self
.property_map
.keys()
68 # Recursively expands text keys in the form of $KEY$ with the value
69 # of the property of the same name. Since this is done recursively
70 # one property can be defined in terms of another.
71 def Replace(self
, text
):
72 itr
= IDLPropertyNode
.regex_var
.finditer(text
)
75 (start
, stop
) = m
.span()
76 if m
.lastgroup
== 'src':
77 out
+= text
[start
:stop
]
78 if m
.lastgroup
== 'key':
79 key
= text
[start
+1:stop
-1]
80 val
= self
.GetProperty(key
, None)
82 self
.Error('No property "%s"' % key
)
83 out
+= self
.Replace(str(val
))
91 # Build a property node, setting the properties including a name, and
92 # associate the children with this new node.
94 def BuildNode(name
, props
, children
=[], parents
=[]):
95 node
= IDLPropertyNode()
96 node
.SetProperty('NAME', name
)
98 toks
= prop
.split('=')
99 node
.SetProperty(toks
[0], toks
[1])
100 for child
in children
:
101 child
.AddParent(node
)
102 for parent
in parents
:
103 node
.AddParent(parent
)
106 def ExpectProp(node
, name
, val
):
107 found
= node
.GetProperty(name
)
109 ErrOut
.Log('Got property %s expecting %s' % (found
, val
))
114 # Verify property inheritance
118 left
= BuildNode('Left', ['Left=Left'])
119 right
= BuildNode('Right', ['Right=Right'])
120 top
= BuildNode('Top', ['Left=Top', 'Right=Top'], [left
, right
])
122 errors
+= ExpectProp(top
, 'Left', 'Top')
123 errors
+= ExpectProp(top
, 'Right', 'Top')
125 errors
+= ExpectProp(left
, 'Left', 'Left')
126 errors
+= ExpectProp(left
, 'Right', 'Top')
128 errors
+= ExpectProp(right
, 'Left', 'Top')
129 errors
+= ExpectProp(right
, 'Right', 'Right')
131 if not errors
: InfoOut
.Log('Passed PropertyTest')
135 def ExpectText(node
, text
, val
):
136 found
= node
.Replace(text
)
138 ErrOut
.Log('Got replacement %s expecting %s' % (found
, val
))
143 # Verify text replacement
147 left
= BuildNode('Left', ['Left=Left'])
148 right
= BuildNode('Right', ['Right=Right'])
149 top
= BuildNode('Top', ['Left=Top', 'Right=Top'], [left
, right
])
151 errors
+= ExpectText(top
, '$Left$', 'Top')
152 errors
+= ExpectText(top
, '$Right$', 'Top')
154 errors
+= ExpectText(left
, '$Left$', 'Left')
155 errors
+= ExpectText(left
, '$Right$', 'Top')
157 errors
+= ExpectText(right
, '$Left$', 'Top')
158 errors
+= ExpectText(right
, '$Right$', 'Right')
160 if not errors
: InfoOut
.Log('Passed ReplaceTest')
164 def MultiParentTest():
167 parent1
= BuildNode('parent1', ['PARENT1=parent1', 'TOPMOST=$TOP$'])
168 parent2
= BuildNode('parent2', ['PARENT1=parent2', 'PARENT2=parent2'])
169 child
= BuildNode('child', ['CHILD=child'], parents
=[parent1
, parent2
])
170 BuildNode('top', ['TOP=top'], children
=[parent1
])
172 errors
+= ExpectText(child
, '$CHILD$', 'child')
173 errors
+= ExpectText(child
, '$PARENT1$', 'parent1')
174 errors
+= ExpectText(child
, '$PARENT2$', 'parent2')
176 # Verify recursive resolution
177 errors
+= ExpectText(child
, '$TOPMOST$', 'top')
179 if not errors
: InfoOut
.Log('Passed MultiParentTest')
185 errors
+= PropertyTest()
186 errors
+= ReplaceTest()
187 errors
+= MultiParentTest()
190 ErrOut
.Log('IDLNode failed with %d errors.' % errors
)
195 if __name__
== '__main__':