1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/simplified/utils.py Fri Apr 06 00:53:18 2007 +0200
1.3 @@ -0,0 +1,167 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Simplified program utilities.
1.8 +
1.9 +Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This software is free software; you can redistribute it and/or
1.12 +modify it under the terms of the GNU General Public License as
1.13 +published by the Free Software Foundation; either version 2 of
1.14 +the License, or (at your option) any later version.
1.15 +
1.16 +This software is distributed in the hope that it will be useful,
1.17 +but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 +GNU General Public License for more details.
1.20 +
1.21 +You should have received a copy of the GNU General Public
1.22 +License along with this library; see the file LICENCE.txt
1.23 +If not, write to the Free Software Foundation, Inc.,
1.24 +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.25 +"""
1.26 +
1.27 +from compiler.visitor import ASTVisitor
1.28 +
1.29 +# Exceptions.
1.30 +
1.31 +class SimplifiedError(Exception):
1.32 +
1.33 + "An error in the annotation process."
1.34 +
1.35 + def __init__(self, exc, node, *args):
1.36 +
1.37 + """
1.38 + Initialise the error with an existing exception 'exc', the 'node' at
1.39 + which this error occurs, along with additional optional arguments.
1.40 + """
1.41 +
1.42 + Exception.__init__(self, *args)
1.43 + self.nodes = [node]
1.44 + self.exc = exc
1.45 +
1.46 + def add(self, node):
1.47 +
1.48 + "Add the given 'node' to the path of nodes leading from the exception."
1.49 +
1.50 + self.nodes.append(node)
1.51 +
1.52 + def __str__(self):
1.53 +
1.54 + "Return a string showing the principal exception details."
1.55 +
1.56 + return "%s, %s" % (self.exc, self.nodes)
1.57 +
1.58 +# Elementary visitor support.
1.59 +
1.60 +class Visitor(ASTVisitor):
1.61 +
1.62 + "A visitor base class."
1.63 +
1.64 + def __init__(self):
1.65 + ASTVisitor.__init__(self)
1.66 +
1.67 + def default(self, node, *args):
1.68 + raise SimplifiedError, (None, node)
1.69 +
1.70 + def dispatch(self, node, *args):
1.71 + return ASTVisitor.dispatch(self, node, *args)
1.72 +
1.73 + def dispatches(self, nodes, *args):
1.74 + results = []
1.75 + for node in nodes:
1.76 + results.append(self.dispatch(node, *args))
1.77 + return results
1.78 +
1.79 + def dispatch_dict(self, d, *args):
1.80 + results = {}
1.81 + for name, node in d.items():
1.82 + results[name] = self.dispatch(node, *args)
1.83 + return results
1.84 +
1.85 +# Unique name registration.
1.86 +
1.87 +class Naming:
1.88 +
1.89 + "Maintain records of unique names for each simple name."
1.90 +
1.91 + index_separator = "-"
1.92 +
1.93 + def __init__(self):
1.94 + self.names = {}
1.95 +
1.96 + def get(self, obj):
1.97 + return obj._unique_name
1.98 +
1.99 + def set(self, obj, name):
1.100 + if hasattr(obj, "_unique_name"):
1.101 + return
1.102 + if not self.names.has_key(name):
1.103 + self.names[name] = 0
1.104 + n = self.names[name] + 1
1.105 + self.names[name] = n
1.106 + obj._unique_name = "%s%s%d" % (name, self.index_separator, n)
1.107 +
1.108 +def name(obj, name):
1.109 +
1.110 + "Return a unique name for the given 'obj', indicating the base 'name'."
1.111 +
1.112 + naming.set(obj, name)
1.113 + return naming.get(obj)
1.114 +
1.115 +# Naming singleton.
1.116 +
1.117 +naming = Naming()
1.118 +
1.119 +# Named nodes are those which can be referenced in some way.
1.120 +
1.121 +class WithName:
1.122 +
1.123 + "Node naming."
1.124 +
1.125 + def __init__(self):
1.126 +
1.127 + "Initialise the object's full name."
1.128 +
1.129 + self._full_name = name(self, self.name or "$untitled")
1.130 +
1.131 + def full_name(self):
1.132 +
1.133 + "Return the object's full name."
1.134 +
1.135 + return self._full_name
1.136 +
1.137 +# Comparable nodes based on naming.
1.138 +
1.139 +class Comparable:
1.140 +
1.141 + "Comparable nodes implementing the 'full_name' method."
1.142 +
1.143 + def __eq__(self, other):
1.144 +
1.145 + "This object is equal to 'other' if the full names are the same."
1.146 +
1.147 + # NOTE: Single instance: all instances are the same
1.148 + # NOTE: Multiple instances: all instances are different
1.149 + if hasattr(other, "full_name"):
1.150 + return self.full_name() == other.full_name()
1.151 + else:
1.152 + return NotImplemented
1.153 +
1.154 + def __hash__(self):
1.155 +
1.156 + "The hash of this object is based on its full name."
1.157 +
1.158 + return hash(self.full_name())
1.159 +
1.160 +# Structure nodes indicating namespace-bearing objects.
1.161 +
1.162 +class Structure(Comparable):
1.163 +
1.164 + "A non-program node containing some kind of namespace."
1.165 +
1.166 + def __init__(self, **kw):
1.167 + for name, value in kw.items():
1.168 + setattr(self, name, value)
1.169 +
1.170 +# vim: tabstop=4 expandtab shiftwidth=4