| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  | """Generate ast module from specification
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This script generates the ast module from a simple specification, | 
					
						
							|  |  |  | which makes it easy to accomodate changes in the grammar.  This | 
					
						
							|  |  |  | approach would be quite reasonable if the grammar changed often. | 
					
						
							|  |  |  | Instead, it is rather complex to generate the appropriate code.  And | 
					
						
							|  |  |  | the Node interface has changed more often than the grammar. | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import fileinput | 
					
						
							|  |  |  | import getopt | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | from StringIO import StringIO | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SPEC = "ast.txt" | 
					
						
							|  |  |  | COMMA = ", " | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def load_boilerplate(file): | 
					
						
							|  |  |  |     f = open(file) | 
					
						
							|  |  |  |     buf = f.read() | 
					
						
							|  |  |  |     f.close() | 
					
						
							|  |  |  |     i = buf.find('### ''PROLOGUE') | 
					
						
							|  |  |  |     j = buf.find('### ''EPILOGUE') | 
					
						
							|  |  |  |     pro = buf[i+12:j].strip() | 
					
						
							|  |  |  |     epi = buf[j+12:].strip() | 
					
						
							|  |  |  |     return pro, epi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def strip_default(arg): | 
					
						
							|  |  |  |     """Return the argname from an 'arg = default' string""" | 
					
						
							|  |  |  |     i = arg.find('=') | 
					
						
							|  |  |  |     if i == -1: | 
					
						
							|  |  |  |         return arg | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |     t = arg[:i].strip() | 
					
						
							|  |  |  |     return t | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | P_NODE = 1 | 
					
						
							|  |  |  | P_OTHER = 2 | 
					
						
							|  |  |  | P_NESTED = 3 | 
					
						
							|  |  |  | P_NONE = 4 | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class NodeInfo: | 
					
						
							|  |  |  |     """Each instance describes a specific AST node""" | 
					
						
							|  |  |  |     def __init__(self, name, args): | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.args = args.strip() | 
					
						
							|  |  |  |         self.argnames = self.get_argnames() | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         self.argprops = self.get_argprops() | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         self.nargs = len(self.argnames) | 
					
						
							|  |  |  |         self.init = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def get_argnames(self): | 
					
						
							|  |  |  |         if '(' in self.args: | 
					
						
							|  |  |  |             i = self.args.find('(') | 
					
						
							|  |  |  |             j = self.args.rfind(')') | 
					
						
							|  |  |  |             args = self.args[i+1:j] | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             args = self.args | 
					
						
							|  |  |  |         return [strip_default(arg.strip()) | 
					
						
							|  |  |  |                 for arg in args.split(',') if arg] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |     def get_argprops(self): | 
					
						
							|  |  |  |         """Each argument can have a property like '*' or '!'
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         XXX This method modifies the argnames in place! | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         d = {} | 
					
						
							|  |  |  |         hardest_arg = P_NODE | 
					
						
							|  |  |  |         for i in range(len(self.argnames)): | 
					
						
							|  |  |  |             arg = self.argnames[i] | 
					
						
							|  |  |  |             if arg.endswith('*'): | 
					
						
							|  |  |  |                 arg = self.argnames[i] = arg[:-1] | 
					
						
							|  |  |  |                 d[arg] = P_OTHER | 
					
						
							| 
									
										
										
										
											2001-09-17 20:16:30 +00:00
										 |  |  |                 hardest_arg = max(hardest_arg, P_OTHER) | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |             elif arg.endswith('!'): | 
					
						
							|  |  |  |                 arg = self.argnames[i] = arg[:-1] | 
					
						
							|  |  |  |                 d[arg] = P_NESTED | 
					
						
							| 
									
										
										
										
											2001-09-17 20:16:30 +00:00
										 |  |  |                 hardest_arg = max(hardest_arg, P_NESTED) | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |             elif arg.endswith('&'): | 
					
						
							|  |  |  |                 arg = self.argnames[i] = arg[:-1] | 
					
						
							|  |  |  |                 d[arg] = P_NONE | 
					
						
							| 
									
										
										
										
											2001-09-17 20:16:30 +00:00
										 |  |  |                 hardest_arg = max(hardest_arg, P_NONE) | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 d[arg] = P_NODE | 
					
						
							|  |  |  |         self.hardest_arg = hardest_arg | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if hardest_arg > P_NODE: | 
					
						
							|  |  |  |             self.args = self.args.replace('*', '') | 
					
						
							|  |  |  |             self.args = self.args.replace('!', '') | 
					
						
							|  |  |  |             self.args = self.args.replace('&', '') | 
					
						
							| 
									
										
										
										
											2004-07-18 06:16:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         return d | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |     def gen_source(self): | 
					
						
							|  |  |  |         buf = StringIO() | 
					
						
							|  |  |  |         print >> buf, "class %s(Node):" % self.name | 
					
						
							|  |  |  |         self._gen_init(buf) | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         print >> buf | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         self._gen_getChildren(buf) | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         print >> buf | 
					
						
							|  |  |  |         self._gen_getChildNodes(buf) | 
					
						
							|  |  |  |         print >> buf | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         self._gen_repr(buf) | 
					
						
							|  |  |  |         buf.seek(0, 0) | 
					
						
							|  |  |  |         return buf.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _gen_init(self, buf): | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  |         if self.args: | 
					
						
							|  |  |  |             print >> buf, "    def __init__(self, %s, lineno=None):" % self.args | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print >> buf, "    def __init__(self, lineno=None):" | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         if self.argnames: | 
					
						
							|  |  |  |             for name in self.argnames: | 
					
						
							|  |  |  |                 print >> buf, "        self.%s = %s" % (name, name) | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  |         print >> buf, "        self.lineno = lineno" | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         if self.init: | 
					
						
							|  |  |  |             print >> buf, "".join(["    " + line for line in self.init]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _gen_getChildren(self, buf): | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         print >> buf, "    def getChildren(self):" | 
					
						
							|  |  |  |         if len(self.argnames) == 0: | 
					
						
							|  |  |  |             print >> buf, "        return ()" | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |             if self.hardest_arg < P_NESTED: | 
					
						
							|  |  |  |                 clist = COMMA.join(["self.%s" % c | 
					
						
							|  |  |  |                                     for c in self.argnames]) | 
					
						
							|  |  |  |                 if self.nargs == 1: | 
					
						
							|  |  |  |                     print >> buf, "        return %s," % clist | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     print >> buf, "        return %s" % clist | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  |                 if len(self.argnames) == 1: | 
					
						
							|  |  |  |                     print >> buf, "        return tuple(flatten(self.%s))" % self.argnames[0] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     print >> buf, "        children = []" | 
					
						
							|  |  |  |                     template = "        children.%s(%sself.%s%s)" | 
					
						
							|  |  |  |                     for name in self.argnames: | 
					
						
							|  |  |  |                         if self.argprops[name] == P_NESTED: | 
					
						
							|  |  |  |                             print >> buf, template % ("extend", "flatten(", | 
					
						
							|  |  |  |                                                       name, ")") | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             print >> buf, template % ("append", "", name, "") | 
					
						
							|  |  |  |                     print >> buf, "        return tuple(children)" | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _gen_getChildNodes(self, buf): | 
					
						
							|  |  |  |         print >> buf, "    def getChildNodes(self):" | 
					
						
							|  |  |  |         if len(self.argnames) == 0: | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |             print >> buf, "        return ()" | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             if self.hardest_arg < P_NESTED: | 
					
						
							|  |  |  |                 clist = ["self.%s" % c | 
					
						
							|  |  |  |                          for c in self.argnames | 
					
						
							|  |  |  |                          if self.argprops[c] == P_NODE] | 
					
						
							|  |  |  |                 if len(clist) == 0: | 
					
						
							|  |  |  |                     print >> buf, "        return ()" | 
					
						
							|  |  |  |                 elif len(clist) == 1: | 
					
						
							|  |  |  |                     print >> buf, "        return %s," % clist[0] | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     print >> buf, "        return %s" % COMMA.join(clist) | 
					
						
							|  |  |  |             else: | 
					
						
							| 
									
										
										
										
											2004-08-02 06:10:11 +00:00
										 |  |  |                 print >> buf, "        nodelist = []" | 
					
						
							|  |  |  |                 template = "        nodelist.%s(%sself.%s%s)" | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |                 for name in self.argnames: | 
					
						
							|  |  |  |                     if self.argprops[name] == P_NONE: | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  |                         tmp = ("        if self.%s is not None:\n" | 
					
						
							| 
									
										
										
										
											2004-08-02 06:10:11 +00:00
										 |  |  |                                "            nodelist.append(self.%s)") | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |                         print >> buf, tmp % (name, name) | 
					
						
							|  |  |  |                     elif self.argprops[name] == P_NESTED: | 
					
						
							|  |  |  |                         print >> buf, template % ("extend", "flatten_nodes(", | 
					
						
							|  |  |  |                                                   name, ")") | 
					
						
							|  |  |  |                     elif self.argprops[name] == P_NODE: | 
					
						
							|  |  |  |                         print >> buf, template % ("append", "", name, "") | 
					
						
							| 
									
										
										
										
											2004-08-02 06:10:11 +00:00
										 |  |  |                 print >> buf, "        return tuple(nodelist)" | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _gen_repr(self, buf): | 
					
						
							|  |  |  |         print >> buf, "    def __repr__(self):" | 
					
						
							|  |  |  |         if self.argnames: | 
					
						
							|  |  |  |             fmt = COMMA.join(["%s"] * self.nargs) | 
					
						
							| 
									
										
										
										
											2001-08-18 00:14:37 +00:00
										 |  |  |             if '(' in self.args: | 
					
						
							|  |  |  |                 fmt = '(%s)' % fmt | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |             vals = ["repr(self.%s)" % name for name in self.argnames] | 
					
						
							|  |  |  |             vals = COMMA.join(vals) | 
					
						
							|  |  |  |             if self.nargs == 1: | 
					
						
							|  |  |  |                 vals = vals + "," | 
					
						
							|  |  |  |             print >> buf, '        return "%s(%s)" %% (%s)' % \ | 
					
						
							|  |  |  |                   (self.name, fmt, vals) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             print >> buf, '        return "%s()"' % self.name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | rx_init = re.compile('init\((.*)\):') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_spec(file): | 
					
						
							|  |  |  |     classes = {} | 
					
						
							|  |  |  |     cur = None | 
					
						
							|  |  |  |     for line in fileinput.input(file): | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         if line.strip().startswith('#'): | 
					
						
							|  |  |  |             continue | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         mo = rx_init.search(line) | 
					
						
							|  |  |  |         if mo is None: | 
					
						
							|  |  |  |             if cur is None: | 
					
						
							|  |  |  |                 # a normal entry | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     name, args = line.split(':') | 
					
						
							|  |  |  |                 except ValueError: | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |                 classes[name] = NodeInfo(name, args) | 
					
						
							|  |  |  |                 cur = None | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 # some code for the __init__ method | 
					
						
							|  |  |  |                 cur.init.append(line) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # some extra code for a Node's __init__ method | 
					
						
							|  |  |  |             name = mo.group(1) | 
					
						
							|  |  |  |             cur = classes[name] | 
					
						
							| 
									
										
										
										
											2004-08-02 06:10:11 +00:00
										 |  |  |     return sorted(classes.values(), key=lambda n: n.name) | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     prologue, epilogue = load_boilerplate(sys.argv[-1]) | 
					
						
							|  |  |  |     print prologue | 
					
						
							|  |  |  |     print | 
					
						
							|  |  |  |     classes = parse_spec(SPEC) | 
					
						
							|  |  |  |     for info in classes: | 
					
						
							|  |  |  |         print info.gen_source() | 
					
						
							|  |  |  |     print epilogue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     main() | 
					
						
							|  |  |  |     sys.exit(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### PROLOGUE | 
					
						
							|  |  |  | """Python abstract syntax node definitions
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  | This file is automatically generated by Tools/compiler/astgen.py | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | from consts import CO_VARARGS, CO_VARKEYWORDS | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-02 05:55:20 +00:00
										 |  |  | def flatten(seq): | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |     l = [] | 
					
						
							| 
									
										
										
										
											2005-06-02 05:55:20 +00:00
										 |  |  |     for elt in seq: | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |         t = type(elt) | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  |         if t is tuple or t is list: | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |             for elt2 in flatten(elt): | 
					
						
							|  |  |  |                 l.append(elt2) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             l.append(elt) | 
					
						
							|  |  |  |     return l | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-06-02 05:55:20 +00:00
										 |  |  | def flatten_nodes(seq): | 
					
						
							|  |  |  |     return [n for n in flatten(seq) if isinstance(n, Node)] | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | nodes = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  | class Node: | 
					
						
							|  |  |  |     """Abstract base class for ast nodes.""" | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  |     def getChildren(self): | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         pass # implemented by subclasses | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  |     def __iter__(self): | 
					
						
							|  |  |  |         for n in self.getChildren(): | 
					
						
							|  |  |  |             yield n | 
					
						
							|  |  |  |     def asList(self): # for backwards compatibility | 
					
						
							|  |  |  |         return self.getChildren() | 
					
						
							| 
									
										
										
										
											2001-08-14 18:58:00 +00:00
										 |  |  |     def getChildNodes(self): | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |         pass # implemented by subclasses | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class EmptyNode(Node): | 
					
						
							| 
									
										
										
										
											2001-08-29 18:08:02 +00:00
										 |  |  |     pass | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-08-02 06:10:11 +00:00
										 |  |  | class Expression(Node): | 
					
						
							|  |  |  |     # Expression is an artificial node class to support "eval" | 
					
						
							|  |  |  |     nodes["expression"] = "Expression" | 
					
						
							|  |  |  |     def __init__(self, node): | 
					
						
							|  |  |  |         self.node = node | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getChildren(self): | 
					
						
							|  |  |  |         return self.node, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getChildNodes(self): | 
					
						
							|  |  |  |         return self.node, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return "Expression(%s)" % (repr(self.node)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-10-25 17:59:17 +00:00
										 |  |  | ### EPILOGUE | 
					
						
							| 
									
										
										
										
											2004-09-07 15:28:01 +00:00
										 |  |  | for name, obj in globals().items(): | 
					
						
							|  |  |  |     if isinstance(obj, type) and issubclass(obj, Node): | 
					
						
							| 
									
										
										
										
											2004-09-12 03:49:31 +00:00
										 |  |  |         nodes[name.lower()] = obj |