# HG changeset patch # User Paul Boddie # Date 1340751752 -7200 # Node ID 1805fbc407add84465ea3c16433a202d4921064f # Parent b10bea64619cb06ace6b7dd028f259d1baf59899 Made separate modules for object set support and some basic data structures (instance, constant), mix-ins and related utilities. Moved the location abstraction into the program module. diff -r b10bea64619c -r 1805fbc407ad micropython/__init__.py --- a/micropython/__init__.py Tue Jun 26 23:49:49 2012 +0200 +++ b/micropython/__init__.py Wed Jun 27 01:02:32 2012 +0200 @@ -39,6 +39,7 @@ from micropython.common import * from micropython.data import * +from micropython.program import Location import micropython.ast import micropython.native import micropython.opt diff -r b10bea64619c -r 1805fbc407ad micropython/basicdata.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/micropython/basicdata.py Wed Jun 27 01:02:32 2012 +0200 @@ -0,0 +1,124 @@ +#!/usr/bin/env python + +""" +Fundamental program data structure abstractions. + +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +# Short representation display support. + +def shortrepr(obj): + if obj is None: + return repr(None) + else: + return obj.__shortrepr__() + +# Mix-ins and abstract classes. + +class Naming: + + "A mix-in providing naming conveniences." + + def full_name(self): + if self.name is not None: + return self.parent.full_name() + "." + self.name + else: + return self.parent.full_name() + +# Instances are special in that they need to be wrapped together with context in +# a running program, but they are not generally constant. + +class Instance: + + "A placeholder indicating the involvement of an instance." + + def __init__(self): + self.parent = None + + # Image generation details. + + self.location = None + + def __repr__(self): + return "" + + def __eq__(self, other): + return other.__class__ is Instance + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return 0 + + __shortrepr__ = __repr__ + +# Common instance construction. + +common_instance = Instance() + +def make_instance(): + return common_instance + +class Constant: + + "A superclass for all constant or context-free structures." + + pass + +# Data objects appearing in programs before run-time. + +class Const(Constant, Instance): + + "A constant object with no context." + + def __init__(self, value): + Instance.__init__(self) + self.value = value + + def get_value(self): + return self.value + + def __repr__(self): + if self.location is not None: + return "Const(%r, location=%r)" % (self.value, self.location) + else: + return "Const(%r)" % self.value + + __shortrepr__ = __repr__ + + # Support constants as dictionary keys in order to build constant tables. + + def __eq__(self, other): + return other is not None and isinstance(other, Const) and \ + self.value == other.value and self.value.__class__ is other.value.__class__ + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return hash(self.value) + + # Constants are instances of various built-in types. + + def value_type_name(self): + return ".".join(self.value_type_name_parts()) + + def value_type_name_parts(self): + return "__builtins__", self.value.__class__.__name__ + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r b10bea64619c -r 1805fbc407ad micropython/common.py --- a/micropython/common.py Tue Jun 26 23:49:49 2012 +0200 +++ b/micropython/common.py Wed Jun 27 01:02:32 2012 +0200 @@ -19,256 +19,9 @@ this program. If not, see . """ -import operator +from micropython.basicdata import Instance import sys -try: - set -except NameError: - from sets import Set as set - -class ObjectSet: - - "A set of objects with optional associated data." - - def __init__(self, d=None): - if d is None: - self.objects = {} - elif hasattr(d, "items"): - self.objects = dict(d) - else: - self.objects = {} - for key in d: - self.add(key) - - def __repr__(self): - out = ["{"] - first = 1 - for key, value in self.items(): - if not first: - out.append(", ") - else: - first = 0 - out.append(repr(key)) - if value: - out.append(" : ") - out.append(repr(value)) - out.append("}") - return "".join(out) - - def __iter__(self): - return iter(self.keys()) - - def __nonzero__(self): - return self.objects != {} - - # List methods. - - def __add__(self, other): - obj = ObjectSet(self) - for key in other: - obj.add(key) - return obj - - # Set membership and comparisons. - - def __hash__(self): - l = self.keys() - l.sort() - return hash(tuple(l)) - - def __eq__(self, other): - if hasattr(other, "objects"): - return self.objects == other.objects - else: - return set(self.objects.keys()) == set(other) - - # Set methods. - - def add(self, obj): - if not self.has_key(obj): - self[obj] = set() - - def issubset(self, other): - return set(self).issubset(other) - - # Dictionary and related methods. - - def __getitem__(self, key): - return self.objects[key] - - def get(self, key, default=None): - return self.objects.get(key, default) - - def __setitem__(self, key, value): - self.objects[key] = value - - def has_key(self, key): - return self.objects.has_key(key) - - def keys(self): - return self.objects.keys() - - def values(self): - return self.objects.values() - - def items(self): - return self.objects.items() - - def update(self, other): - - # Combining dictionary-like objects involves combining values. - - if hasattr(other, "items"): - for key, value in other.items(): - self[key] = add_sets(value, self.get(key, [])) - - # Combining sequence-like objects involves just adding members. - - else: - for key in other: - self.add(key) - - def merge(self, other): - - """ - Merge this object set with an 'other' set, combining the values where - possible, and incorporating values present in only one of the sets. - """ - - return combine(self, other, ObjectSet(), add_sets) - -def deepen_mapping_dict(d): - - "Convert the values of 'd' to be elements of a potentially larger set." - - new_dict = {} - for key, value in d.items(): - if value is None: - new_dict[key] = None - else: - new_dict[key] = ObjectSet([value]) - return new_dict - -def merge_mapping_dicts(dicts): - - "Merge the given 'dicts' mapping keys to sets of objects." - - new_dict = {} - update_mapping_dict(new_dict, dicts) - return new_dict - -def update_mapping_dict(new_dict, dicts): - - """ - Update 'new_dict' with the contents of the set dictionary 'dicts'. - None entries may be incorporated into object sets. For example: - - d1: {'a' : None} - d2: {'a' : x} - -> {'a' : {None, x}} - - Here, None might be used to represent an empty set and x may be an existing - set. - """ - - for old_dict in dicts: - for key, value in old_dict.items(): - - # Add existing mappings within an object set. - - if not new_dict.has_key(key): - if value is not None: - new_dict[key] = ObjectSet(value) - else: - new_dict[key] = None - elif new_dict[key] is not None: - if value is not None: - new_dict[key].update(value) - else: - new_dict[key].add(value) - else: - if value is not None: - objset = new_dict[key] = ObjectSet(value) - objset.add(None) - -def combine_mapping_dicts(d1, d2): - - """ - Combine dictionaries 'd1' and 'd2' in a resulting dictionary, with the - values of the contributing dictionaries being themselves combined such that - a "product" of the values for a given key are stored in the combined - dictionary. - - For example: - - d1: {'a' : [{'f', 'g'}, {'f', 'h'}], ...} - d2: {'a' : [{'f'}, {'e', 'f', 'g'}], ...} - -> {'a' : [{'f', 'g'}, {'f', 'h'}, {'e', 'f', 'g'}, {'e', 'f', 'g', 'h'}], ...} - - Note that items of 'd2' whose keys are not in 'd1' are not added to 'd1' - since this, in the context of propagating attribute usage observations, - would result in spurious usage details being made available in places where - the names may not have been defined. - """ - - return combine(d1, d2, {}, combine_object_set_lists, True) - -def combine(d1, d2, combined, combine_op, only_d1_keys=False): - - """ - Combine dictionaries 'd1' and 'd2' in the 'combined' object provided, using - the 'combine_op' to merge values from the dictionaries. - - If 'only_d1_keys' is set to a true value, items from 'd2' employing keys not - in 'd1' will not be added to 'd1'. - """ - - if d2 is not None: - d2_keys = d2.keys() - - for key in d2_keys: - if not d1.has_key(key): - if not only_d1_keys: - combined[key] = d2[key] - else: - combined[key] = combine_op(d1[key], d2[key]) - else: - d2_keys = () - - for key in d1.keys(): - if key not in d2_keys: - combined[key] = d1[key] - - return combined - -def combine_object_set_lists(l1, l2): - - """ - Combine lists of object sets 'l1' and 'l2' to make a product of their - members. - """ - - # If either list is undefined (indicated by None), return the defined list, - # or return None if neither is defined. - - if l1 is None: - if l2 is None: - return None - else: - return l2 + [] - elif l2 is None: - return l1 + [] - - combined = ObjectSet() - for i1 in l1: - for i2 in l2: - combined.add(i1.merge(i2)) - return combined - -def add_sets(s1, s2): - return set(list(s1) + list(s2)) - # Visitors and activities related to node annotations. class ASTVisitor: @@ -507,43 +260,6 @@ def __repr__(self): return "AtLeast(%r)" % self.count -class Location: - - """ - A special representation for locations which are to be compared to program - objects. - """ - - def __init__(self, location): - self.location = location - - def _op(self, other, op): - if hasattr(other, "location"): - return op(self.location, other.location) - else: - raise NotImplemented - - def __eq__(self, other): - return self._op(other, operator.eq) - - def __ne__(self, other): - return self._op(other, operator.ne) - - def __lt__(self, other): - return self._op(other, operator.lt) - - def __le__(self, other): - return self._op(other, operator.le) - - def __gt__(self, other): - return self._op(other, operator.gt) - - def __ge__(self, other): - return self._op(other, operator.ge) - - def __repr__(self): - return "Location(%r)" % self.location - # Useful data. operator_functions = { diff -r b10bea64619c -r 1805fbc407ad micropython/data.py --- a/micropython/data.py Tue Jun 26 23:49:49 2012 +0200 +++ b/micropython/data.py Wed Jun 27 01:02:32 2012 +0200 @@ -53,37 +53,11 @@ """ from micropython.program import ReplaceableContext, PlaceholderContext +from micropython.basicdata import * from micropython.common import * +from micropython.objectset import * import sys -def shortrepr(obj): - if obj is None: - return repr(None) - else: - return obj.__shortrepr__() - -lambda_index = 0 - -def new_lambda(): - - "Return a new sequence number for a lambda definition." - - global lambda_index - lambda_index += 1 - return lambda_index - -# Mix-ins and abstract classes. - -class Naming: - - "A mix-in providing naming conveniences." - - def full_name(self): - if self.name is not None: - return self.parent.full_name() + "." + self.name - else: - return self.parent.full_name() - class NamespaceDict: "A mix-in providing dictionary methods." @@ -1233,86 +1207,6 @@ l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) return ", ".join(l) -# Instances are special in that they need to be wrapped together with context in -# a running program, but they are not generally constant. - -class Instance: - - "A placeholder indicating the involvement of an instance." - - def __init__(self): - self.parent = None - - # Image generation details. - - self.location = None - - def __repr__(self): - return "" - - def __eq__(self, other): - return other.__class__ is Instance - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return 0 - - __shortrepr__ = __repr__ - -common_instance = Instance() - -def make_instance(): - return common_instance - -class Constant: - - "A superclass for all constant or context-free structures." - - pass - -# Data objects appearing in programs before run-time. - -class Const(Constant, Instance): - - "A constant object with no context." - - def __init__(self, value): - Instance.__init__(self) - self.value = value - - def get_value(self): - return self.value - - def __repr__(self): - if self.location is not None: - return "Const(%r, location=%r)" % (self.value, self.location) - else: - return "Const(%r)" % self.value - - __shortrepr__ = __repr__ - - # Support constants as dictionary keys in order to build constant tables. - - def __eq__(self, other): - return other is not None and isinstance(other, Const) and \ - self.value == other.value and self.value.__class__ is other.value.__class__ - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return hash(self.value) - - # Constants are instances of various built-in types. - - def value_type_name(self): - return ".".join(self.value_type_name_parts()) - - def value_type_name_parts(self): - return "__builtins__", self.value.__class__.__name__ - class Class(NamespaceDict, Naming, Constant): "A base class for common/normal classes and the type class." @@ -2162,4 +2056,16 @@ else: return CommonClass(name, parent, module, node) +# Lambda sequence numbering. + +lambda_index = 0 + +def new_lambda(): + + "Return a new sequence number for a lambda definition." + + global lambda_index + lambda_index += 1 + return lambda_index + # vim: tabstop=4 expandtab shiftwidth=4 diff -r b10bea64619c -r 1805fbc407ad micropython/objectset.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/micropython/objectset.py Wed Jun 27 01:02:32 2012 +0200 @@ -0,0 +1,271 @@ +#!/usr/bin/env python + +""" +Object set support. + +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +import operator + +try: + set +except NameError: + from sets import Set as set + +class ObjectSet: + + "A set of objects with optional associated data." + + def __init__(self, d=None): + if d is None: + self.objects = {} + elif hasattr(d, "items"): + self.objects = dict(d) + else: + self.objects = {} + for key in d: + self.add(key) + + def __repr__(self): + out = ["{"] + first = 1 + for key, value in self.items(): + if not first: + out.append(", ") + else: + first = 0 + out.append(repr(key)) + if value: + out.append(" : ") + out.append(repr(value)) + out.append("}") + return "".join(out) + + def __iter__(self): + return iter(self.keys()) + + def __nonzero__(self): + return self.objects != {} + + # List methods. + + def __add__(self, other): + obj = ObjectSet(self) + for key in other: + obj.add(key) + return obj + + # Set membership and comparisons. + + def __hash__(self): + l = self.keys() + l.sort() + return hash(tuple(l)) + + def __eq__(self, other): + if hasattr(other, "objects"): + return self.objects == other.objects + else: + return set(self.objects.keys()) == set(other) + + # Set methods. + + def add(self, obj): + if not self.has_key(obj): + self[obj] = set() + + def issubset(self, other): + return set(self).issubset(other) + + # Dictionary and related methods. + + def __getitem__(self, key): + return self.objects[key] + + def get(self, key, default=None): + return self.objects.get(key, default) + + def __setitem__(self, key, value): + self.objects[key] = value + + def has_key(self, key): + return self.objects.has_key(key) + + def keys(self): + return self.objects.keys() + + def values(self): + return self.objects.values() + + def items(self): + return self.objects.items() + + def update(self, other): + + # Combining dictionary-like objects involves combining values. + + if hasattr(other, "items"): + for key, value in other.items(): + self[key] = add_sets(value, self.get(key, [])) + + # Combining sequence-like objects involves just adding members. + + else: + for key in other: + self.add(key) + + def merge(self, other): + + """ + Merge this object set with an 'other' set, combining the values where + possible, and incorporating values present in only one of the sets. + """ + + return combine(self, other, ObjectSet(), add_sets) + +def deepen_mapping_dict(d): + + "Convert the values of 'd' to be elements of a potentially larger set." + + new_dict = {} + for key, value in d.items(): + if value is None: + new_dict[key] = None + else: + new_dict[key] = ObjectSet([value]) + return new_dict + +def merge_mapping_dicts(dicts): + + "Merge the given 'dicts' mapping keys to sets of objects." + + new_dict = {} + update_mapping_dict(new_dict, dicts) + return new_dict + +def update_mapping_dict(new_dict, dicts): + + """ + Update 'new_dict' with the contents of the set dictionary 'dicts'. + None entries may be incorporated into object sets. For example: + + d1: {'a' : None} + d2: {'a' : x} + -> {'a' : {None, x}} + + Here, None might be used to represent an empty set and x may be an existing + set. + """ + + for old_dict in dicts: + for key, value in old_dict.items(): + + # Add existing mappings within an object set. + + if not new_dict.has_key(key): + if value is not None: + new_dict[key] = ObjectSet(value) + else: + new_dict[key] = None + elif new_dict[key] is not None: + if value is not None: + new_dict[key].update(value) + else: + new_dict[key].add(value) + else: + if value is not None: + objset = new_dict[key] = ObjectSet(value) + objset.add(None) + +def combine_mapping_dicts(d1, d2): + + """ + Combine dictionaries 'd1' and 'd2' in a resulting dictionary, with the + values of the contributing dictionaries being themselves combined such that + a "product" of the values for a given key are stored in the combined + dictionary. + + For example: + + d1: {'a' : [{'f', 'g'}, {'f', 'h'}], ...} + d2: {'a' : [{'f'}, {'e', 'f', 'g'}], ...} + -> {'a' : [{'f', 'g'}, {'f', 'h'}, {'e', 'f', 'g'}, {'e', 'f', 'g', 'h'}], ...} + + Note that items of 'd2' whose keys are not in 'd1' are not added to 'd1' + since this, in the context of propagating attribute usage observations, + would result in spurious usage details being made available in places where + the names may not have been defined. + """ + + return combine(d1, d2, {}, combine_object_set_lists, True) + +def combine(d1, d2, combined, combine_op, only_d1_keys=False): + + """ + Combine dictionaries 'd1' and 'd2' in the 'combined' object provided, using + the 'combine_op' to merge values from the dictionaries. + + If 'only_d1_keys' is set to a true value, items from 'd2' employing keys not + in 'd1' will not be added to 'd1'. + """ + + if d2 is not None: + d2_keys = d2.keys() + + for key in d2_keys: + if not d1.has_key(key): + if not only_d1_keys: + combined[key] = d2[key] + else: + combined[key] = combine_op(d1[key], d2[key]) + else: + d2_keys = () + + for key in d1.keys(): + if key not in d2_keys: + combined[key] = d1[key] + + return combined + +def combine_object_set_lists(l1, l2): + + """ + Combine lists of object sets 'l1' and 'l2' to make a product of their + members. + """ + + # If either list is undefined (indicated by None), return the defined list, + # or return None if neither is defined. + + if l1 is None: + if l2 is None: + return None + else: + return l2 + [] + elif l2 is None: + return l1 + [] + + combined = ObjectSet() + for i1 in l1: + for i2 in l2: + combined.add(i1.merge(i2)) + return combined + +def add_sets(s1, s2): + return set(list(s1) + list(s2)) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r b10bea64619c -r 1805fbc407ad micropython/program.py --- a/micropython/program.py Tue Jun 26 23:49:49 2012 +0200 +++ b/micropython/program.py Wed Jun 27 01:02:32 2012 +0200 @@ -3,7 +3,7 @@ """ Program code and data representations. -Copyright (C) 2009, 2011 Paul Boddie +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,6 +19,43 @@ this program. If not, see . """ +class Location: + + """ + A special representation for locations which are to be compared to program + objects. + """ + + def __init__(self, location): + self.location = location + + def _op(self, other, op): + if hasattr(other, "location"): + return op(self.location, other.location) + else: + raise NotImplemented + + def __eq__(self, other): + return self._op(other, operator.eq) + + def __ne__(self, other): + return self._op(other, operator.ne) + + def __lt__(self, other): + return self._op(other, operator.lt) + + def __le__(self, other): + return self._op(other, operator.le) + + def __gt__(self, other): + return self._op(other, operator.gt) + + def __ge__(self, other): + return self._op(other, operator.ge) + + def __repr__(self): + return "Location(%r)" % self.location + class Block: "A code block."