| Trees | Indices | Help |
|
|---|
|
|
1 """Assignment utilities for the Jazz Parser.
2
3 These are generic tools for assignments. They can be used for different
4 sorts of assignment and are useful for unification frameworks (e.g.
5 the music_roman unification procedure).
6
7 """
8 """
9 ============================== License ========================================
10 Copyright (C) 2008, 2010-12 University of Edinburgh, Mark Granroth-Wilding
11
12 This file is part of The Jazz Parser.
13
14 The Jazz Parser is free software: you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 The Jazz Parser is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with The Jazz Parser. If not, see <http://www.gnu.org/licenses/>.
26
27 ============================ End license ======================================
28
29 """
30 __author__ = "Mark Granroth-Wilding <mark.granroth-wilding@ed.ac.uk>"
31
32 import logging
33 # Get the logger from the logging system
34 logger = logging.getLogger("main_logger")
35
36
38 """
39 A special kind of dict that stores not only a mapping from keys to
40 values, but also equivalence classes of keys. Manages the equivalence
41 classes so that values get assigned to all the keys as soon as
42 one of them is given a value.
43 """
45 super(EquivalenceAssignment, self).__init__(*args, **kwargs)
46 self.classes = []
47 self.inconsistent = False
48
50 """
51 Return the equivalence class including the key, if one
52 exists, removing from the list of classes.
53 """
54 for i,cls in enumerate(self.classes):
55 if key in cls:
56 return self.classes.pop(i)
57 return None
58
64
66 # Check the equivalence classes for other keys equivalent to this one
67 cls = self._pop_class(key)
68 if key in self and self[key] is not None:
69 # We already have a value for this key.
70 # Resolve the conflict in a way appropriate to the data type.
71 value = self.resolve_conflict(self[key], value)
72 super(EquivalenceAssignment, self).__setitem__(key, value)
73 # Set all the other keys in the equiv class
74 if cls is not None:
75 for eq_key in cls:
76 # This recursively call setitem, but will not find the eq
77 # class again, because we popped it.
78 self[eq_key] = value
79
81 """ Asserts the equivalence of the two keys. """
82 if key1 == key2:
83 # They're equal: no need to assert equivalence
84 return
85 # Look for an existing class for each key
86 key1_class = self._get_class(key1)
87 key2_class = self._get_class(key2)
88 if key1_class is not None and key2_class is not None:
89 if key1_class is key2_class:
90 # They're already equivalent
91 return
92 # Both keys are already in classes. Merge them
93 self.classes.remove(key1_class)
94 self.classes.remove(key2_class)
95 self.classes.append(key1_class | key2_class)
96 elif key1_class is not None:
97 # key1 is already in a class. Add key2
98 key1_class.add(key2)
99 elif key2_class is not None:
100 # key2 is already in a class. Add key1
101 key2_class.add(key1)
102 else:
103 # Neither key was found. Add a new equivalence class
104 self.classes.append(set([key1, key2]))
105 # Added an equivalence: set any values again to make sure the
106 # whole class gets the value
107 if key1 in self:
108 # setitem will take care of the equivalences
109 self[key1] = self[key1]
110 if key2 in self:
111 self[key2] = self[key2]
112
114 """
115 When two values are fighting for the same key, this method
116 decides which to pick, or raises an exception if the conflict
117 cannot be resolved (i.e. incompatible values).
118 By default this raises an exception if the values are not equal.
119 Should be overridden by subclasses.
120 """
121 if old_value != new_value:
122 self.inconsistent = True
123 raise EquivalenceAssignment.IncompatibleAssignmentError, \
124 "%s and %s cannot be assigned to the same key" % (old_value, new_value)
125 return old_value
126
128 if isinstance(ass, EquivalenceAssignment):
129 # Another eq assignment: update including the eq classes
130 for cls in ass.classes:
131 if len(cls) > 1:
132 cls = list(cls)
133 first = cls[0]
134 for other in cls[1:]:
135 self.add_equivalence(first, other)
136 super(EquivalenceAssignment, self).update(ass)
137
139 return "<%s | [%s]>" % (", ".join(["%s=%s" % ass for ass in self.items()]),
140 ",".join(["(%s)" % ",".join(["%s" % key for key in cls]) for cls in self.classes]))
141
144
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Nov 26 16:05:03 2012 | http://epydoc.sourceforge.net |