1.1 --- a/micropython/__init__.py Tue Jun 26 23:49:49 2012 +0200
1.2 +++ b/micropython/__init__.py Wed Jun 27 01:02:32 2012 +0200
1.3 @@ -39,6 +39,7 @@
1.4
1.5 from micropython.common import *
1.6 from micropython.data import *
1.7 +from micropython.program import Location
1.8 import micropython.ast
1.9 import micropython.native
1.10 import micropython.opt
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/micropython/basicdata.py Wed Jun 27 01:02:32 2012 +0200
2.3 @@ -0,0 +1,124 @@
2.4 +#!/usr/bin/env python
2.5 +
2.6 +"""
2.7 +Fundamental program data structure abstractions.
2.8 +
2.9 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
2.10 +
2.11 +This program is free software; you can redistribute it and/or modify it under
2.12 +the terms of the GNU General Public License as published by the Free Software
2.13 +Foundation; either version 3 of the License, or (at your option) any later
2.14 +version.
2.15 +
2.16 +This program is distributed in the hope that it will be useful, but WITHOUT
2.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
2.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
2.19 +details.
2.20 +
2.21 +You should have received a copy of the GNU General Public License along with
2.22 +this program. If not, see <http://www.gnu.org/licenses/>.
2.23 +"""
2.24 +
2.25 +# Short representation display support.
2.26 +
2.27 +def shortrepr(obj):
2.28 + if obj is None:
2.29 + return repr(None)
2.30 + else:
2.31 + return obj.__shortrepr__()
2.32 +
2.33 +# Mix-ins and abstract classes.
2.34 +
2.35 +class Naming:
2.36 +
2.37 + "A mix-in providing naming conveniences."
2.38 +
2.39 + def full_name(self):
2.40 + if self.name is not None:
2.41 + return self.parent.full_name() + "." + self.name
2.42 + else:
2.43 + return self.parent.full_name()
2.44 +
2.45 +# Instances are special in that they need to be wrapped together with context in
2.46 +# a running program, but they are not generally constant.
2.47 +
2.48 +class Instance:
2.49 +
2.50 + "A placeholder indicating the involvement of an instance."
2.51 +
2.52 + def __init__(self):
2.53 + self.parent = None
2.54 +
2.55 + # Image generation details.
2.56 +
2.57 + self.location = None
2.58 +
2.59 + def __repr__(self):
2.60 + return "<instance>"
2.61 +
2.62 + def __eq__(self, other):
2.63 + return other.__class__ is Instance
2.64 +
2.65 + def __ne__(self, other):
2.66 + return not self.__eq__(other)
2.67 +
2.68 + def __hash__(self):
2.69 + return 0
2.70 +
2.71 + __shortrepr__ = __repr__
2.72 +
2.73 +# Common instance construction.
2.74 +
2.75 +common_instance = Instance()
2.76 +
2.77 +def make_instance():
2.78 + return common_instance
2.79 +
2.80 +class Constant:
2.81 +
2.82 + "A superclass for all constant or context-free structures."
2.83 +
2.84 + pass
2.85 +
2.86 +# Data objects appearing in programs before run-time.
2.87 +
2.88 +class Const(Constant, Instance):
2.89 +
2.90 + "A constant object with no context."
2.91 +
2.92 + def __init__(self, value):
2.93 + Instance.__init__(self)
2.94 + self.value = value
2.95 +
2.96 + def get_value(self):
2.97 + return self.value
2.98 +
2.99 + def __repr__(self):
2.100 + if self.location is not None:
2.101 + return "Const(%r, location=%r)" % (self.value, self.location)
2.102 + else:
2.103 + return "Const(%r)" % self.value
2.104 +
2.105 + __shortrepr__ = __repr__
2.106 +
2.107 + # Support constants as dictionary keys in order to build constant tables.
2.108 +
2.109 + def __eq__(self, other):
2.110 + return other is not None and isinstance(other, Const) and \
2.111 + self.value == other.value and self.value.__class__ is other.value.__class__
2.112 +
2.113 + def __ne__(self, other):
2.114 + return not self.__eq__(other)
2.115 +
2.116 + def __hash__(self):
2.117 + return hash(self.value)
2.118 +
2.119 + # Constants are instances of various built-in types.
2.120 +
2.121 + def value_type_name(self):
2.122 + return ".".join(self.value_type_name_parts())
2.123 +
2.124 + def value_type_name_parts(self):
2.125 + return "__builtins__", self.value.__class__.__name__
2.126 +
2.127 +# vim: tabstop=4 expandtab shiftwidth=4
3.1 --- a/micropython/common.py Tue Jun 26 23:49:49 2012 +0200
3.2 +++ b/micropython/common.py Wed Jun 27 01:02:32 2012 +0200
3.3 @@ -19,256 +19,9 @@
3.4 this program. If not, see <http://www.gnu.org/licenses/>.
3.5 """
3.6
3.7 -import operator
3.8 +from micropython.basicdata import Instance
3.9 import sys
3.10
3.11 -try:
3.12 - set
3.13 -except NameError:
3.14 - from sets import Set as set
3.15 -
3.16 -class ObjectSet:
3.17 -
3.18 - "A set of objects with optional associated data."
3.19 -
3.20 - def __init__(self, d=None):
3.21 - if d is None:
3.22 - self.objects = {}
3.23 - elif hasattr(d, "items"):
3.24 - self.objects = dict(d)
3.25 - else:
3.26 - self.objects = {}
3.27 - for key in d:
3.28 - self.add(key)
3.29 -
3.30 - def __repr__(self):
3.31 - out = ["{"]
3.32 - first = 1
3.33 - for key, value in self.items():
3.34 - if not first:
3.35 - out.append(", ")
3.36 - else:
3.37 - first = 0
3.38 - out.append(repr(key))
3.39 - if value:
3.40 - out.append(" : ")
3.41 - out.append(repr(value))
3.42 - out.append("}")
3.43 - return "".join(out)
3.44 -
3.45 - def __iter__(self):
3.46 - return iter(self.keys())
3.47 -
3.48 - def __nonzero__(self):
3.49 - return self.objects != {}
3.50 -
3.51 - # List methods.
3.52 -
3.53 - def __add__(self, other):
3.54 - obj = ObjectSet(self)
3.55 - for key in other:
3.56 - obj.add(key)
3.57 - return obj
3.58 -
3.59 - # Set membership and comparisons.
3.60 -
3.61 - def __hash__(self):
3.62 - l = self.keys()
3.63 - l.sort()
3.64 - return hash(tuple(l))
3.65 -
3.66 - def __eq__(self, other):
3.67 - if hasattr(other, "objects"):
3.68 - return self.objects == other.objects
3.69 - else:
3.70 - return set(self.objects.keys()) == set(other)
3.71 -
3.72 - # Set methods.
3.73 -
3.74 - def add(self, obj):
3.75 - if not self.has_key(obj):
3.76 - self[obj] = set()
3.77 -
3.78 - def issubset(self, other):
3.79 - return set(self).issubset(other)
3.80 -
3.81 - # Dictionary and related methods.
3.82 -
3.83 - def __getitem__(self, key):
3.84 - return self.objects[key]
3.85 -
3.86 - def get(self, key, default=None):
3.87 - return self.objects.get(key, default)
3.88 -
3.89 - def __setitem__(self, key, value):
3.90 - self.objects[key] = value
3.91 -
3.92 - def has_key(self, key):
3.93 - return self.objects.has_key(key)
3.94 -
3.95 - def keys(self):
3.96 - return self.objects.keys()
3.97 -
3.98 - def values(self):
3.99 - return self.objects.values()
3.100 -
3.101 - def items(self):
3.102 - return self.objects.items()
3.103 -
3.104 - def update(self, other):
3.105 -
3.106 - # Combining dictionary-like objects involves combining values.
3.107 -
3.108 - if hasattr(other, "items"):
3.109 - for key, value in other.items():
3.110 - self[key] = add_sets(value, self.get(key, []))
3.111 -
3.112 - # Combining sequence-like objects involves just adding members.
3.113 -
3.114 - else:
3.115 - for key in other:
3.116 - self.add(key)
3.117 -
3.118 - def merge(self, other):
3.119 -
3.120 - """
3.121 - Merge this object set with an 'other' set, combining the values where
3.122 - possible, and incorporating values present in only one of the sets.
3.123 - """
3.124 -
3.125 - return combine(self, other, ObjectSet(), add_sets)
3.126 -
3.127 -def deepen_mapping_dict(d):
3.128 -
3.129 - "Convert the values of 'd' to be elements of a potentially larger set."
3.130 -
3.131 - new_dict = {}
3.132 - for key, value in d.items():
3.133 - if value is None:
3.134 - new_dict[key] = None
3.135 - else:
3.136 - new_dict[key] = ObjectSet([value])
3.137 - return new_dict
3.138 -
3.139 -def merge_mapping_dicts(dicts):
3.140 -
3.141 - "Merge the given 'dicts' mapping keys to sets of objects."
3.142 -
3.143 - new_dict = {}
3.144 - update_mapping_dict(new_dict, dicts)
3.145 - return new_dict
3.146 -
3.147 -def update_mapping_dict(new_dict, dicts):
3.148 -
3.149 - """
3.150 - Update 'new_dict' with the contents of the set dictionary 'dicts'.
3.151 - None entries may be incorporated into object sets. For example:
3.152 -
3.153 - d1: {'a' : None}
3.154 - d2: {'a' : x}
3.155 - -> {'a' : {None, x}}
3.156 -
3.157 - Here, None might be used to represent an empty set and x may be an existing
3.158 - set.
3.159 - """
3.160 -
3.161 - for old_dict in dicts:
3.162 - for key, value in old_dict.items():
3.163 -
3.164 - # Add existing mappings within an object set.
3.165 -
3.166 - if not new_dict.has_key(key):
3.167 - if value is not None:
3.168 - new_dict[key] = ObjectSet(value)
3.169 - else:
3.170 - new_dict[key] = None
3.171 - elif new_dict[key] is not None:
3.172 - if value is not None:
3.173 - new_dict[key].update(value)
3.174 - else:
3.175 - new_dict[key].add(value)
3.176 - else:
3.177 - if value is not None:
3.178 - objset = new_dict[key] = ObjectSet(value)
3.179 - objset.add(None)
3.180 -
3.181 -def combine_mapping_dicts(d1, d2):
3.182 -
3.183 - """
3.184 - Combine dictionaries 'd1' and 'd2' in a resulting dictionary, with the
3.185 - values of the contributing dictionaries being themselves combined such that
3.186 - a "product" of the values for a given key are stored in the combined
3.187 - dictionary.
3.188 -
3.189 - For example:
3.190 -
3.191 - d1: {'a' : [{'f', 'g'}, {'f', 'h'}], ...}
3.192 - d2: {'a' : [{'f'}, {'e', 'f', 'g'}], ...}
3.193 - -> {'a' : [{'f', 'g'}, {'f', 'h'}, {'e', 'f', 'g'}, {'e', 'f', 'g', 'h'}], ...}
3.194 -
3.195 - Note that items of 'd2' whose keys are not in 'd1' are not added to 'd1'
3.196 - since this, in the context of propagating attribute usage observations,
3.197 - would result in spurious usage details being made available in places where
3.198 - the names may not have been defined.
3.199 - """
3.200 -
3.201 - return combine(d1, d2, {}, combine_object_set_lists, True)
3.202 -
3.203 -def combine(d1, d2, combined, combine_op, only_d1_keys=False):
3.204 -
3.205 - """
3.206 - Combine dictionaries 'd1' and 'd2' in the 'combined' object provided, using
3.207 - the 'combine_op' to merge values from the dictionaries.
3.208 -
3.209 - If 'only_d1_keys' is set to a true value, items from 'd2' employing keys not
3.210 - in 'd1' will not be added to 'd1'.
3.211 - """
3.212 -
3.213 - if d2 is not None:
3.214 - d2_keys = d2.keys()
3.215 -
3.216 - for key in d2_keys:
3.217 - if not d1.has_key(key):
3.218 - if not only_d1_keys:
3.219 - combined[key] = d2[key]
3.220 - else:
3.221 - combined[key] = combine_op(d1[key], d2[key])
3.222 - else:
3.223 - d2_keys = ()
3.224 -
3.225 - for key in d1.keys():
3.226 - if key not in d2_keys:
3.227 - combined[key] = d1[key]
3.228 -
3.229 - return combined
3.230 -
3.231 -def combine_object_set_lists(l1, l2):
3.232 -
3.233 - """
3.234 - Combine lists of object sets 'l1' and 'l2' to make a product of their
3.235 - members.
3.236 - """
3.237 -
3.238 - # If either list is undefined (indicated by None), return the defined list,
3.239 - # or return None if neither is defined.
3.240 -
3.241 - if l1 is None:
3.242 - if l2 is None:
3.243 - return None
3.244 - else:
3.245 - return l2 + []
3.246 - elif l2 is None:
3.247 - return l1 + []
3.248 -
3.249 - combined = ObjectSet()
3.250 - for i1 in l1:
3.251 - for i2 in l2:
3.252 - combined.add(i1.merge(i2))
3.253 - return combined
3.254 -
3.255 -def add_sets(s1, s2):
3.256 - return set(list(s1) + list(s2))
3.257 -
3.258 # Visitors and activities related to node annotations.
3.259
3.260 class ASTVisitor:
3.261 @@ -507,43 +260,6 @@
3.262 def __repr__(self):
3.263 return "AtLeast(%r)" % self.count
3.264
3.265 -class Location:
3.266 -
3.267 - """
3.268 - A special representation for locations which are to be compared to program
3.269 - objects.
3.270 - """
3.271 -
3.272 - def __init__(self, location):
3.273 - self.location = location
3.274 -
3.275 - def _op(self, other, op):
3.276 - if hasattr(other, "location"):
3.277 - return op(self.location, other.location)
3.278 - else:
3.279 - raise NotImplemented
3.280 -
3.281 - def __eq__(self, other):
3.282 - return self._op(other, operator.eq)
3.283 -
3.284 - def __ne__(self, other):
3.285 - return self._op(other, operator.ne)
3.286 -
3.287 - def __lt__(self, other):
3.288 - return self._op(other, operator.lt)
3.289 -
3.290 - def __le__(self, other):
3.291 - return self._op(other, operator.le)
3.292 -
3.293 - def __gt__(self, other):
3.294 - return self._op(other, operator.gt)
3.295 -
3.296 - def __ge__(self, other):
3.297 - return self._op(other, operator.ge)
3.298 -
3.299 - def __repr__(self):
3.300 - return "Location(%r)" % self.location
3.301 -
3.302 # Useful data.
3.303
3.304 operator_functions = {
4.1 --- a/micropython/data.py Tue Jun 26 23:49:49 2012 +0200
4.2 +++ b/micropython/data.py Wed Jun 27 01:02:32 2012 +0200
4.3 @@ -53,37 +53,11 @@
4.4 """
4.5
4.6 from micropython.program import ReplaceableContext, PlaceholderContext
4.7 +from micropython.basicdata import *
4.8 from micropython.common import *
4.9 +from micropython.objectset import *
4.10 import sys
4.11
4.12 -def shortrepr(obj):
4.13 - if obj is None:
4.14 - return repr(None)
4.15 - else:
4.16 - return obj.__shortrepr__()
4.17 -
4.18 -lambda_index = 0
4.19 -
4.20 -def new_lambda():
4.21 -
4.22 - "Return a new sequence number for a lambda definition."
4.23 -
4.24 - global lambda_index
4.25 - lambda_index += 1
4.26 - return lambda_index
4.27 -
4.28 -# Mix-ins and abstract classes.
4.29 -
4.30 -class Naming:
4.31 -
4.32 - "A mix-in providing naming conveniences."
4.33 -
4.34 - def full_name(self):
4.35 - if self.name is not None:
4.36 - return self.parent.full_name() + "." + self.name
4.37 - else:
4.38 - return self.parent.full_name()
4.39 -
4.40 class NamespaceDict:
4.41
4.42 "A mix-in providing dictionary methods."
4.43 @@ -1233,86 +1207,6 @@
4.44 l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v)))
4.45 return ", ".join(l)
4.46
4.47 -# Instances are special in that they need to be wrapped together with context in
4.48 -# a running program, but they are not generally constant.
4.49 -
4.50 -class Instance:
4.51 -
4.52 - "A placeholder indicating the involvement of an instance."
4.53 -
4.54 - def __init__(self):
4.55 - self.parent = None
4.56 -
4.57 - # Image generation details.
4.58 -
4.59 - self.location = None
4.60 -
4.61 - def __repr__(self):
4.62 - return "<instance>"
4.63 -
4.64 - def __eq__(self, other):
4.65 - return other.__class__ is Instance
4.66 -
4.67 - def __ne__(self, other):
4.68 - return not self.__eq__(other)
4.69 -
4.70 - def __hash__(self):
4.71 - return 0
4.72 -
4.73 - __shortrepr__ = __repr__
4.74 -
4.75 -common_instance = Instance()
4.76 -
4.77 -def make_instance():
4.78 - return common_instance
4.79 -
4.80 -class Constant:
4.81 -
4.82 - "A superclass for all constant or context-free structures."
4.83 -
4.84 - pass
4.85 -
4.86 -# Data objects appearing in programs before run-time.
4.87 -
4.88 -class Const(Constant, Instance):
4.89 -
4.90 - "A constant object with no context."
4.91 -
4.92 - def __init__(self, value):
4.93 - Instance.__init__(self)
4.94 - self.value = value
4.95 -
4.96 - def get_value(self):
4.97 - return self.value
4.98 -
4.99 - def __repr__(self):
4.100 - if self.location is not None:
4.101 - return "Const(%r, location=%r)" % (self.value, self.location)
4.102 - else:
4.103 - return "Const(%r)" % self.value
4.104 -
4.105 - __shortrepr__ = __repr__
4.106 -
4.107 - # Support constants as dictionary keys in order to build constant tables.
4.108 -
4.109 - def __eq__(self, other):
4.110 - return other is not None and isinstance(other, Const) and \
4.111 - self.value == other.value and self.value.__class__ is other.value.__class__
4.112 -
4.113 - def __ne__(self, other):
4.114 - return not self.__eq__(other)
4.115 -
4.116 - def __hash__(self):
4.117 - return hash(self.value)
4.118 -
4.119 - # Constants are instances of various built-in types.
4.120 -
4.121 - def value_type_name(self):
4.122 - return ".".join(self.value_type_name_parts())
4.123 -
4.124 - def value_type_name_parts(self):
4.125 - return "__builtins__", self.value.__class__.__name__
4.126 -
4.127 class Class(NamespaceDict, Naming, Constant):
4.128
4.129 "A base class for common/normal classes and the type class."
4.130 @@ -2162,4 +2056,16 @@
4.131 else:
4.132 return CommonClass(name, parent, module, node)
4.133
4.134 +# Lambda sequence numbering.
4.135 +
4.136 +lambda_index = 0
4.137 +
4.138 +def new_lambda():
4.139 +
4.140 + "Return a new sequence number for a lambda definition."
4.141 +
4.142 + global lambda_index
4.143 + lambda_index += 1
4.144 + return lambda_index
4.145 +
4.146 # vim: tabstop=4 expandtab shiftwidth=4
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/micropython/objectset.py Wed Jun 27 01:02:32 2012 +0200
5.3 @@ -0,0 +1,271 @@
5.4 +#!/usr/bin/env python
5.5 +
5.6 +"""
5.7 +Object set support.
5.8 +
5.9 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
5.10 +
5.11 +This program is free software; you can redistribute it and/or modify it under
5.12 +the terms of the GNU General Public License as published by the Free Software
5.13 +Foundation; either version 3 of the License, or (at your option) any later
5.14 +version.
5.15 +
5.16 +This program is distributed in the hope that it will be useful, but WITHOUT
5.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
5.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
5.19 +details.
5.20 +
5.21 +You should have received a copy of the GNU General Public License along with
5.22 +this program. If not, see <http://www.gnu.org/licenses/>.
5.23 +"""
5.24 +
5.25 +import operator
5.26 +
5.27 +try:
5.28 + set
5.29 +except NameError:
5.30 + from sets import Set as set
5.31 +
5.32 +class ObjectSet:
5.33 +
5.34 + "A set of objects with optional associated data."
5.35 +
5.36 + def __init__(self, d=None):
5.37 + if d is None:
5.38 + self.objects = {}
5.39 + elif hasattr(d, "items"):
5.40 + self.objects = dict(d)
5.41 + else:
5.42 + self.objects = {}
5.43 + for key in d:
5.44 + self.add(key)
5.45 +
5.46 + def __repr__(self):
5.47 + out = ["{"]
5.48 + first = 1
5.49 + for key, value in self.items():
5.50 + if not first:
5.51 + out.append(", ")
5.52 + else:
5.53 + first = 0
5.54 + out.append(repr(key))
5.55 + if value:
5.56 + out.append(" : ")
5.57 + out.append(repr(value))
5.58 + out.append("}")
5.59 + return "".join(out)
5.60 +
5.61 + def __iter__(self):
5.62 + return iter(self.keys())
5.63 +
5.64 + def __nonzero__(self):
5.65 + return self.objects != {}
5.66 +
5.67 + # List methods.
5.68 +
5.69 + def __add__(self, other):
5.70 + obj = ObjectSet(self)
5.71 + for key in other:
5.72 + obj.add(key)
5.73 + return obj
5.74 +
5.75 + # Set membership and comparisons.
5.76 +
5.77 + def __hash__(self):
5.78 + l = self.keys()
5.79 + l.sort()
5.80 + return hash(tuple(l))
5.81 +
5.82 + def __eq__(self, other):
5.83 + if hasattr(other, "objects"):
5.84 + return self.objects == other.objects
5.85 + else:
5.86 + return set(self.objects.keys()) == set(other)
5.87 +
5.88 + # Set methods.
5.89 +
5.90 + def add(self, obj):
5.91 + if not self.has_key(obj):
5.92 + self[obj] = set()
5.93 +
5.94 + def issubset(self, other):
5.95 + return set(self).issubset(other)
5.96 +
5.97 + # Dictionary and related methods.
5.98 +
5.99 + def __getitem__(self, key):
5.100 + return self.objects[key]
5.101 +
5.102 + def get(self, key, default=None):
5.103 + return self.objects.get(key, default)
5.104 +
5.105 + def __setitem__(self, key, value):
5.106 + self.objects[key] = value
5.107 +
5.108 + def has_key(self, key):
5.109 + return self.objects.has_key(key)
5.110 +
5.111 + def keys(self):
5.112 + return self.objects.keys()
5.113 +
5.114 + def values(self):
5.115 + return self.objects.values()
5.116 +
5.117 + def items(self):
5.118 + return self.objects.items()
5.119 +
5.120 + def update(self, other):
5.121 +
5.122 + # Combining dictionary-like objects involves combining values.
5.123 +
5.124 + if hasattr(other, "items"):
5.125 + for key, value in other.items():
5.126 + self[key] = add_sets(value, self.get(key, []))
5.127 +
5.128 + # Combining sequence-like objects involves just adding members.
5.129 +
5.130 + else:
5.131 + for key in other:
5.132 + self.add(key)
5.133 +
5.134 + def merge(self, other):
5.135 +
5.136 + """
5.137 + Merge this object set with an 'other' set, combining the values where
5.138 + possible, and incorporating values present in only one of the sets.
5.139 + """
5.140 +
5.141 + return combine(self, other, ObjectSet(), add_sets)
5.142 +
5.143 +def deepen_mapping_dict(d):
5.144 +
5.145 + "Convert the values of 'd' to be elements of a potentially larger set."
5.146 +
5.147 + new_dict = {}
5.148 + for key, value in d.items():
5.149 + if value is None:
5.150 + new_dict[key] = None
5.151 + else:
5.152 + new_dict[key] = ObjectSet([value])
5.153 + return new_dict
5.154 +
5.155 +def merge_mapping_dicts(dicts):
5.156 +
5.157 + "Merge the given 'dicts' mapping keys to sets of objects."
5.158 +
5.159 + new_dict = {}
5.160 + update_mapping_dict(new_dict, dicts)
5.161 + return new_dict
5.162 +
5.163 +def update_mapping_dict(new_dict, dicts):
5.164 +
5.165 + """
5.166 + Update 'new_dict' with the contents of the set dictionary 'dicts'.
5.167 + None entries may be incorporated into object sets. For example:
5.168 +
5.169 + d1: {'a' : None}
5.170 + d2: {'a' : x}
5.171 + -> {'a' : {None, x}}
5.172 +
5.173 + Here, None might be used to represent an empty set and x may be an existing
5.174 + set.
5.175 + """
5.176 +
5.177 + for old_dict in dicts:
5.178 + for key, value in old_dict.items():
5.179 +
5.180 + # Add existing mappings within an object set.
5.181 +
5.182 + if not new_dict.has_key(key):
5.183 + if value is not None:
5.184 + new_dict[key] = ObjectSet(value)
5.185 + else:
5.186 + new_dict[key] = None
5.187 + elif new_dict[key] is not None:
5.188 + if value is not None:
5.189 + new_dict[key].update(value)
5.190 + else:
5.191 + new_dict[key].add(value)
5.192 + else:
5.193 + if value is not None:
5.194 + objset = new_dict[key] = ObjectSet(value)
5.195 + objset.add(None)
5.196 +
5.197 +def combine_mapping_dicts(d1, d2):
5.198 +
5.199 + """
5.200 + Combine dictionaries 'd1' and 'd2' in a resulting dictionary, with the
5.201 + values of the contributing dictionaries being themselves combined such that
5.202 + a "product" of the values for a given key are stored in the combined
5.203 + dictionary.
5.204 +
5.205 + For example:
5.206 +
5.207 + d1: {'a' : [{'f', 'g'}, {'f', 'h'}], ...}
5.208 + d2: {'a' : [{'f'}, {'e', 'f', 'g'}], ...}
5.209 + -> {'a' : [{'f', 'g'}, {'f', 'h'}, {'e', 'f', 'g'}, {'e', 'f', 'g', 'h'}], ...}
5.210 +
5.211 + Note that items of 'd2' whose keys are not in 'd1' are not added to 'd1'
5.212 + since this, in the context of propagating attribute usage observations,
5.213 + would result in spurious usage details being made available in places where
5.214 + the names may not have been defined.
5.215 + """
5.216 +
5.217 + return combine(d1, d2, {}, combine_object_set_lists, True)
5.218 +
5.219 +def combine(d1, d2, combined, combine_op, only_d1_keys=False):
5.220 +
5.221 + """
5.222 + Combine dictionaries 'd1' and 'd2' in the 'combined' object provided, using
5.223 + the 'combine_op' to merge values from the dictionaries.
5.224 +
5.225 + If 'only_d1_keys' is set to a true value, items from 'd2' employing keys not
5.226 + in 'd1' will not be added to 'd1'.
5.227 + """
5.228 +
5.229 + if d2 is not None:
5.230 + d2_keys = d2.keys()
5.231 +
5.232 + for key in d2_keys:
5.233 + if not d1.has_key(key):
5.234 + if not only_d1_keys:
5.235 + combined[key] = d2[key]
5.236 + else:
5.237 + combined[key] = combine_op(d1[key], d2[key])
5.238 + else:
5.239 + d2_keys = ()
5.240 +
5.241 + for key in d1.keys():
5.242 + if key not in d2_keys:
5.243 + combined[key] = d1[key]
5.244 +
5.245 + return combined
5.246 +
5.247 +def combine_object_set_lists(l1, l2):
5.248 +
5.249 + """
5.250 + Combine lists of object sets 'l1' and 'l2' to make a product of their
5.251 + members.
5.252 + """
5.253 +
5.254 + # If either list is undefined (indicated by None), return the defined list,
5.255 + # or return None if neither is defined.
5.256 +
5.257 + if l1 is None:
5.258 + if l2 is None:
5.259 + return None
5.260 + else:
5.261 + return l2 + []
5.262 + elif l2 is None:
5.263 + return l1 + []
5.264 +
5.265 + combined = ObjectSet()
5.266 + for i1 in l1:
5.267 + for i2 in l2:
5.268 + combined.add(i1.merge(i2))
5.269 + return combined
5.270 +
5.271 +def add_sets(s1, s2):
5.272 + return set(list(s1) + list(s2))
5.273 +
5.274 +# vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/micropython/program.py Tue Jun 26 23:49:49 2012 +0200
6.2 +++ b/micropython/program.py Wed Jun 27 01:02:32 2012 +0200
6.3 @@ -3,7 +3,7 @@
6.4 """
6.5 Program code and data representations.
6.6
6.7 -Copyright (C) 2009, 2011 Paul Boddie <paul@boddie.org.uk>
6.8 +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk>
6.9
6.10 This program is free software; you can redistribute it and/or modify it under
6.11 the terms of the GNU General Public License as published by the Free Software
6.12 @@ -19,6 +19,43 @@
6.13 this program. If not, see <http://www.gnu.org/licenses/>.
6.14 """
6.15
6.16 +class Location:
6.17 +
6.18 + """
6.19 + A special representation for locations which are to be compared to program
6.20 + objects.
6.21 + """
6.22 +
6.23 + def __init__(self, location):
6.24 + self.location = location
6.25 +
6.26 + def _op(self, other, op):
6.27 + if hasattr(other, "location"):
6.28 + return op(self.location, other.location)
6.29 + else:
6.30 + raise NotImplemented
6.31 +
6.32 + def __eq__(self, other):
6.33 + return self._op(other, operator.eq)
6.34 +
6.35 + def __ne__(self, other):
6.36 + return self._op(other, operator.ne)
6.37 +
6.38 + def __lt__(self, other):
6.39 + return self._op(other, operator.lt)
6.40 +
6.41 + def __le__(self, other):
6.42 + return self._op(other, operator.le)
6.43 +
6.44 + def __gt__(self, other):
6.45 + return self._op(other, operator.gt)
6.46 +
6.47 + def __ge__(self, other):
6.48 + return self._op(other, operator.ge)
6.49 +
6.50 + def __repr__(self):
6.51 + return "Location(%r)" % self.location
6.52 +
6.53 class Block:
6.54
6.55 "A code block."