blob: caf0974fc1e15898c4478e636b36a5553235bc93 [file] [log] [blame]
[email protected]faff5fc72011-07-14 15:59:041#!/usr/bin/python
2#
3# Copyright (c) 2011 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7""" Hierarchical property system for IDL AST """
8import re
9import sys
10
11from idl_log import ErrOut, InfoOut, WarnOut
12from idl_option import GetOption, Option, ParseOptions
13
14#
15# IDLPropertyNode
16#
17# A property node is a hierarchically aware system for mapping
18# keys to values, such that a local dictionary is search first,
19# followed by parent dictionaries in order.
20#
21class IDLPropertyNode(object):
22 def __init__(self):
23 self.parents = []
24 self.property_map = {}
25
26 def Error(self, msg):
27 name = self.GetProperty('NAME', 'Unknown')
28 parents = [parent.GetProperty('NAME', '???') for parent in self.parents]
29 ErrOut.Log('%s [%s] : %s' % (name, ' '.join(parents), msg))
30
31 def AddParent(self, parent):
32 assert parent
33 self.parents.append(parent)
34
35 def SetProperty(self, name, val):
36 self.property_map[name] = val
37
38 def _GetProperty_(self, name):
39 # Check locally for the property, and return it if found.
40 prop = self.property_map.get(name, None)
41 if prop is not None: return prop
42 # If not, seach parents in order
43 for parent in self.parents:
44 prop = parent.GetProperty(name)
45 if prop is not None: return prop
46 # Otherwise, it can not be found.
47 return None
48
49 def GetProperty(self, name, default=None):
50 prop = self._GetProperty_(name)
51 if prop is None:
52 return default
53 else:
54 return prop
55
56 def GetPropertyLocal(self, name, default=None):
57 # Search for the property, but only locally, returning the
58 # default if not found.
59 prop = self.property_map.get(name, default)
60 return prop
61
62 # Regular expression to parse property keys in a string such that a string
63 # "My string $NAME$" will find the key "NAME".
64 regex_var = re.compile('(?P<src>[^\\$]+)|(?P<key>\\$\\w+\\$)')
65
66 def GetPropertyList(self):
67 return self.property_map.keys()
68
69 # Recursively expands text keys in the form of $KEY$ with the value
70 # of the property of the same name. Since this is done recursively
71 # one property can be defined in terms of another.
72 def Replace(self, text):
73 itr = IDLPropertyNode.regex_var.finditer(text)
74 out = ''
75 for m in itr:
76 (start, stop) = m.span()
77 if m.lastgroup == 'src':
78 out += text[start:stop]
79 if m.lastgroup == 'key':
80 key = text[start+1:stop-1]
81 val = self.GetProperty(key, None)
82 if not val:
83 self.Error('No property "%s"' % key)
84 out += self.Replace(str(val))
85 return out
86
87
88#
89# Testing functions
90#
91
92# Build a property node, setting the properties including a name, and
93# associate the children with this new node.
94#
95def BuildNode(name, props, children=[], parents=[]):
96 node = IDLPropertyNode()
97 node.SetProperty('NAME', name)
98 for prop in props:
99 toks = prop.split('=')
100 node.SetProperty(toks[0], toks[1])
101 for child in children:
102 child.AddParent(node)
103 for parent in parents:
104 node.AddParent(parent)
105 return node
106
107def ExpectProp(node, name, val):
108 found = node.GetProperty(name)
109 if found != val:
110 ErrOut.Log('Got property %s expecting %s' % (found, val))
111 return 1
112 return 0
113
114#
115# Verify property inheritance
116#
117def PropertyTest():
118 errors = 0
119 left = BuildNode('Left', ['Left=Left'])
120 right = BuildNode('Right', ['Right=Right'])
121 top = BuildNode('Top', ['Left=Top', 'Right=Top'], [left, right])
122
123 errors += ExpectProp(top, 'Left', 'Top')
124 errors += ExpectProp(top, 'Right', 'Top')
125
126 errors += ExpectProp(left, 'Left', 'Left')
127 errors += ExpectProp(left, 'Right', 'Top')
128
129 errors += ExpectProp(right, 'Left', 'Top')
130 errors += ExpectProp(right, 'Right', 'Right')
131
132 if not errors: InfoOut.Log('Passed PropertyTest')
133 return errors
134
135
136def ExpectText(node, text, val):
137 found = node.Replace(text)
138 if found != val:
139 ErrOut.Log('Got replacement %s expecting %s' % (found, val))
140 return 1
141 return 0
142
143#
144# Verify text replacement
145#
146def ReplaceTest():
147 errors = 0
148 left = BuildNode('Left', ['Left=Left'])
149 right = BuildNode('Right', ['Right=Right'])
150 top = BuildNode('Top', ['Left=Top', 'Right=Top'], [left, right])
151
152 errors += ExpectText(top, '$Left$', 'Top')
153 errors += ExpectText(top, '$Right$', 'Top')
154
155 errors += ExpectText(left, '$Left$', 'Left')
156 errors += ExpectText(left, '$Right$', 'Top')
157
158 errors += ExpectText(right, '$Left$', 'Top')
159 errors += ExpectText(right, '$Right$', 'Right')
160
161 if not errors: InfoOut.Log('Passed ReplaceTest')
162 return errors
163
164
165def MultiParentTest():
166 errors = 0
167
168 parent1 = BuildNode('parent1', ['PARENT1=parent1', 'TOPMOST=$TOP$'])
169 parent2 = BuildNode('parent2', ['PARENT1=parent2', 'PARENT2=parent2'])
170 child = BuildNode('child', ['CHILD=child'], parents=[parent1, parent2])
171 BuildNode('top', ['TOP=top'], children=[parent1])
172
173 errors += ExpectText(child, '$CHILD$', 'child')
174 errors += ExpectText(child, '$PARENT1$', 'parent1')
175 errors += ExpectText(child, '$PARENT2$', 'parent2')
176
177 # Verify recursive resolution
178 errors += ExpectText(child, '$TOPMOST$', 'top')
179
180 if not errors: InfoOut.Log('Passed MultiParentTest')
181 return errors
182
183def Main():
184 errors = 0
185 errors += PropertyTest()
186 errors += ReplaceTest()
187 errors += MultiParentTest()
188
189 if errors:
190 ErrOut.Log('IDLNode failed with %d errors.' % errors)
191 return -1
192 return 0
193
194if __name__ == '__main__':
195 sys.exit(Main())
196