1 # Licensed under the Apache License, Version 2.0 (the "License");
2 # you may not use this file except in compliance with the License.
3 # You may obtain a copy of the License at
5 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
13 from ...utils.console import puts, Colored, indent
16 # We are inheriting the primitive types in order to add the ability to set
17 # an attribute (_locator) on them.
19 class LocatableString(unicode):
23 class LocatableInt(int):
27 class LocatableFloat(float):
32 if isinstance(value, basestring):
33 return True, LocatableString(value)
34 elif isinstance(value, int) and \
35 not isinstance(value, bool): # Note: bool counts as int in Python!
36 return True, LocatableInt(value)
37 elif isinstance(value, float):
38 return True, LocatableFloat(value)
42 class Locator(object):
44 Stores location information (line and column numbers) for agnostic raw data.
46 def __init__(self, location, line, column, children=None):
47 self.location = location
50 self.children = children
52 def get_child(self, *names):
53 if (not names) or (not isinstance(self.children, dict)):
56 if name not in self.children:
58 child = self.children[name]
59 return child.get_child(names[1:])
61 def link(self, raw, path=None):
62 if hasattr(raw, '_locator'):
63 # This can happen when we use anchors
67 setattr(raw, '_locator', self)
68 except AttributeError:
71 if isinstance(raw, list):
72 for i, raw_element in enumerate(raw):
73 wrapped, raw_element = wrap(raw_element)
76 child_path = '%s.%d' % (path, i) if path else str(i)
78 self.children[i].link(raw_element, child_path)
80 raise ValueError('location map does not match agnostic raw data: %s' %
82 elif isinstance(raw, dict):
83 for k, raw_element in raw.iteritems():
84 wrapped, raw_element = wrap(raw_element)
87 child_path = '%s.%s' % (path, k) if path else k
89 self.children[k].link(raw_element, child_path)
91 raise ValueError('location map does not match agnostic raw data: %s' %
94 def merge(self, locator):
95 if isinstance(self.children, dict) and isinstance(locator.children, dict):
96 for k, loc in locator.children.iteritems():
97 if k in self.children:
98 self.children[k].merge(loc)
100 self.children[k] = loc
102 def dump(self, key=None):
104 puts('%s "%s":%d:%d' %
105 (Colored.red(key), Colored.blue(self.location), self.line, self.column))
107 puts('"%s":%d:%d' % (Colored.blue(self.location), self.line, self.column))
108 if isinstance(self.children, list):
110 for loc in self.children:
112 elif isinstance(self.children, dict):
114 for k, loc in self.children.iteritems():
118 # Should be in same format as Issue.locator_as_str
119 return '"%s":%d:%d' % (self.location, self.line, self.column)