blob: 601d2bddee7f73da484ce7be55e4d3edb9ebe74f [file] [log] [blame]
Jeremy Hylton5477f522001-08-29 18:08:02 +00001"""Generate ast module from specification
2
3This script generates the ast module from a simple specification,
4which makes it easy to accomodate changes in the grammar. This
5approach would be quite reasonable if the grammar changed often.
6Instead, it is rather complex to generate the appropriate code. And
7the Node interface has changed more often than the grammar.
8"""
Jeremy Hylton821eee32000-10-25 17:59:17 +00009
10import fileinput
11import getopt
12import re
13import sys
14from StringIO import StringIO
15
16SPEC = "ast.txt"
17COMMA = ", "
18
19def load_boilerplate(file):
20 f = open(file)
21 buf = f.read()
22 f.close()
23 i = buf.find('### ''PROLOGUE')
24 j = buf.find('### ''EPILOGUE')
25 pro = buf[i+12:j].strip()
26 epi = buf[j+12:].strip()
27 return pro, epi
28
29def strip_default(arg):
30 """Return the argname from an 'arg = default' string"""
31 i = arg.find('=')
32 if i == -1:
33 return arg
Jeremy Hylton5477f522001-08-29 18:08:02 +000034 t = arg[:i].strip()
35 return t
36
37P_NODE = 1
38P_OTHER = 2
39P_NESTED = 3
40P_NONE = 4
Jeremy Hylton821eee32000-10-25 17:59:17 +000041
42class NodeInfo:
43 """Each instance describes a specific AST node"""
44 def __init__(self, name, args):
45 self.name = name
46 self.args = args.strip()
47 self.argnames = self.get_argnames()
Jeremy Hylton5477f522001-08-29 18:08:02 +000048 self.argprops = self.get_argprops()
Jeremy Hylton821eee32000-10-25 17:59:17 +000049 self.nargs = len(self.argnames)
Jeremy Hylton821eee32000-10-25 17:59:17 +000050 self.init = []
51
52 def get_argnames(self):
53 if '(' in self.args:
54 i = self.args.find('(')
55 j = self.args.rfind(')')
56 args = self.args[i+1:j]
57 else:
58 args = self.args
59 return [strip_default(arg.strip())
60 for arg in args.split(',') if arg]
61
Jeremy Hylton5477f522001-08-29 18:08:02 +000062 def get_argprops(self):
63 """Each argument can have a property like '*' or '!'
64
65 XXX This method modifies the argnames in place!
66 """
67 d = {}
68 hardest_arg = P_NODE
69 for i in range(len(self.argnames)):
70 arg = self.argnames[i]
71 if arg.endswith('*'):
72 arg = self.argnames[i] = arg[:-1]
73 d[arg] = P_OTHER
Jeremy Hyltoneab43282001-09-17 20:16:30 +000074 hardest_arg = max(hardest_arg, P_OTHER)
Jeremy Hylton5477f522001-08-29 18:08:02 +000075 elif arg.endswith('!'):
76 arg = self.argnames[i] = arg[:-1]
77 d[arg] = P_NESTED
Jeremy Hyltoneab43282001-09-17 20:16:30 +000078 hardest_arg = max(hardest_arg, P_NESTED)
Jeremy Hylton5477f522001-08-29 18:08:02 +000079 elif arg.endswith('&'):
80 arg = self.argnames[i] = arg[:-1]
81 d[arg] = P_NONE
Jeremy Hyltoneab43282001-09-17 20:16:30 +000082 hardest_arg = max(hardest_arg, P_NONE)
Jeremy Hylton5477f522001-08-29 18:08:02 +000083 else:
84 d[arg] = P_NODE
85 self.hardest_arg = hardest_arg
86
87 if hardest_arg > P_NODE:
88 self.args = self.args.replace('*', '')
89 self.args = self.args.replace('!', '')
90 self.args = self.args.replace('&', '')
Tim Peters182b5ac2004-07-18 06:16:08 +000091
Jeremy Hylton5477f522001-08-29 18:08:02 +000092 return d
93
Jeremy Hylton821eee32000-10-25 17:59:17 +000094 def gen_source(self):
95 buf = StringIO()
Georg Brandld35e9702007-03-18 19:52:24 +000096 print("class %s(Node):" % self.name, file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +000097 self._gen_init(buf)
Georg Brandld35e9702007-03-18 19:52:24 +000098 print(file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +000099 self._gen_getChildren(buf)
Georg Brandld35e9702007-03-18 19:52:24 +0000100 print(file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000101 self._gen_getChildNodes(buf)
Georg Brandld35e9702007-03-18 19:52:24 +0000102 print(file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000103 self._gen_repr(buf)
104 buf.seek(0, 0)
105 return buf.read()
106
107 def _gen_init(self, buf):
Jeremy Hylton566d9342004-09-07 15:28:01 +0000108 if self.args:
Georg Brandld35e9702007-03-18 19:52:24 +0000109 print(" def __init__(self, %s, lineno=None):" % self.args, file=buf)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000110 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000111 print(" def __init__(self, lineno=None):", file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000112 if self.argnames:
113 for name in self.argnames:
Georg Brandld35e9702007-03-18 19:52:24 +0000114 print(" self.%s = %s" % (name, name), file=buf)
115 print(" self.lineno = lineno", file=buf)
Tim Petersca4d08b2006-03-09 22:31:45 +0000116 # Copy the lines in self.init, indented four spaces. The rstrip()
117 # business is to get rid of the four spaces if line happens to be
118 # empty, so that reindent.py is happy with the output.
119 for line in self.init:
Georg Brandld35e9702007-03-18 19:52:24 +0000120 print((" " + line).rstrip(), file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000121
122 def _gen_getChildren(self, buf):
Georg Brandld35e9702007-03-18 19:52:24 +0000123 print(" def getChildren(self):", file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000124 if len(self.argnames) == 0:
Georg Brandld35e9702007-03-18 19:52:24 +0000125 print(" return ()", file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000126 else:
127 if self.hardest_arg < P_NESTED:
128 clist = COMMA.join(["self.%s" % c
129 for c in self.argnames])
130 if self.nargs == 1:
Georg Brandld35e9702007-03-18 19:52:24 +0000131 print(" return %s," % clist, file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000132 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000133 print(" return %s" % clist, file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000134 else:
Jeremy Hylton566d9342004-09-07 15:28:01 +0000135 if len(self.argnames) == 1:
Georg Brandld35e9702007-03-18 19:52:24 +0000136 print(" return tuple(flatten(self.%s))" % self.argnames[0], file=buf)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000137 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000138 print(" children = []", file=buf)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000139 template = " children.%s(%sself.%s%s)"
140 for name in self.argnames:
141 if self.argprops[name] == P_NESTED:
Georg Brandld35e9702007-03-18 19:52:24 +0000142 print(template % ("extend", "flatten(",
143 name, ")"), file=buf)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000144 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000145 print(template % ("append", "", name, ""), file=buf)
146 print(" return tuple(children)", file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000147
148 def _gen_getChildNodes(self, buf):
Georg Brandld35e9702007-03-18 19:52:24 +0000149 print(" def getChildNodes(self):", file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000150 if len(self.argnames) == 0:
Georg Brandld35e9702007-03-18 19:52:24 +0000151 print(" return ()", file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000152 else:
153 if self.hardest_arg < P_NESTED:
154 clist = ["self.%s" % c
155 for c in self.argnames
156 if self.argprops[c] == P_NODE]
157 if len(clist) == 0:
Georg Brandld35e9702007-03-18 19:52:24 +0000158 print(" return ()", file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000159 elif len(clist) == 1:
Georg Brandld35e9702007-03-18 19:52:24 +0000160 print(" return %s," % clist[0], file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000161 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000162 print(" return %s" % COMMA.join(clist), file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000163 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000164 print(" nodelist = []", file=buf)
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000165 template = " nodelist.%s(%sself.%s%s)"
Jeremy Hylton5477f522001-08-29 18:08:02 +0000166 for name in self.argnames:
167 if self.argprops[name] == P_NONE:
Jeremy Hylton566d9342004-09-07 15:28:01 +0000168 tmp = (" if self.%s is not None:\n"
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000169 " nodelist.append(self.%s)")
Georg Brandld35e9702007-03-18 19:52:24 +0000170 print(tmp % (name, name), file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000171 elif self.argprops[name] == P_NESTED:
Georg Brandld35e9702007-03-18 19:52:24 +0000172 print(template % ("extend", "flatten_nodes(",
173 name, ")"), file=buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000174 elif self.argprops[name] == P_NODE:
Georg Brandld35e9702007-03-18 19:52:24 +0000175 print(template % ("append", "", name, ""), file=buf)
176 print(" return tuple(nodelist)", file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000177
178 def _gen_repr(self, buf):
Georg Brandld35e9702007-03-18 19:52:24 +0000179 print(" def __repr__(self):", file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000180 if self.argnames:
181 fmt = COMMA.join(["%s"] * self.nargs)
Jeremy Hyltonab427b82001-08-18 00:14:37 +0000182 if '(' in self.args:
183 fmt = '(%s)' % fmt
Jeremy Hylton821eee32000-10-25 17:59:17 +0000184 vals = ["repr(self.%s)" % name for name in self.argnames]
185 vals = COMMA.join(vals)
186 if self.nargs == 1:
187 vals = vals + ","
Georg Brandld35e9702007-03-18 19:52:24 +0000188 print(' return "%s(%s)" %% (%s)' % \
189 (self.name, fmt, vals), file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000190 else:
Georg Brandld35e9702007-03-18 19:52:24 +0000191 print(' return "%s()"' % self.name, file=buf)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000192
193rx_init = re.compile('init\((.*)\):')
194
195def parse_spec(file):
196 classes = {}
197 cur = None
198 for line in fileinput.input(file):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000199 if line.strip().startswith('#'):
200 continue
Jeremy Hylton821eee32000-10-25 17:59:17 +0000201 mo = rx_init.search(line)
202 if mo is None:
203 if cur is None:
204 # a normal entry
205 try:
206 name, args = line.split(':')
207 except ValueError:
208 continue
209 classes[name] = NodeInfo(name, args)
210 cur = None
211 else:
212 # some code for the __init__ method
213 cur.init.append(line)
214 else:
215 # some extra code for a Node's __init__ method
216 name = mo.group(1)
217 cur = classes[name]
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000218 return sorted(classes.values(), key=lambda n: n.name)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000219
220def main():
221 prologue, epilogue = load_boilerplate(sys.argv[-1])
Georg Brandld35e9702007-03-18 19:52:24 +0000222 print(prologue)
223 print()
Jeremy Hylton821eee32000-10-25 17:59:17 +0000224 classes = parse_spec(SPEC)
225 for info in classes:
Georg Brandld35e9702007-03-18 19:52:24 +0000226 print(info.gen_source())
227 print(epilogue)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000228
229if __name__ == "__main__":
230 main()
231 sys.exit(0)
232
233### PROLOGUE
234"""Python abstract syntax node definitions
235
Jeremy Hylton566d9342004-09-07 15:28:01 +0000236This file is automatically generated by Tools/compiler/astgen.py
Jeremy Hylton821eee32000-10-25 17:59:17 +0000237"""
Guido van Rossum86e58e22006-08-28 15:27:34 +0000238from compiler.consts import CO_VARARGS, CO_VARKEYWORDS
Jeremy Hylton821eee32000-10-25 17:59:17 +0000239
Neil Schemenauerf3694702005-06-02 05:55:20 +0000240def flatten(seq):
Jeremy Hylton821eee32000-10-25 17:59:17 +0000241 l = []
Neil Schemenauerf3694702005-06-02 05:55:20 +0000242 for elt in seq:
Jeremy Hylton821eee32000-10-25 17:59:17 +0000243 t = type(elt)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000244 if t is tuple or t is list:
Jeremy Hylton821eee32000-10-25 17:59:17 +0000245 for elt2 in flatten(elt):
246 l.append(elt2)
247 else:
248 l.append(elt)
249 return l
250
Neil Schemenauerf3694702005-06-02 05:55:20 +0000251def flatten_nodes(seq):
252 return [n for n in flatten(seq) if isinstance(n, Node)]
Jeremy Hylton5477f522001-08-29 18:08:02 +0000253
Jeremy Hylton821eee32000-10-25 17:59:17 +0000254nodes = {}
255
Jeremy Hylton566d9342004-09-07 15:28:01 +0000256class Node:
257 """Abstract base class for ast nodes."""
Jeremy Hylton821eee32000-10-25 17:59:17 +0000258 def getChildren(self):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000259 pass # implemented by subclasses
Jeremy Hylton566d9342004-09-07 15:28:01 +0000260 def __iter__(self):
261 for n in self.getChildren():
262 yield n
263 def asList(self): # for backwards compatibility
264 return self.getChildren()
Jeremy Hyltoneef65902001-08-14 18:58:00 +0000265 def getChildNodes(self):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000266 pass # implemented by subclasses
Jeremy Hylton821eee32000-10-25 17:59:17 +0000267
268class EmptyNode(Node):
Neal Norwitzc1505362006-12-28 06:47:50 +0000269 def getChildNodes(self):
270 return ()
271 def getChildren(self):
272 return ()
Jeremy Hylton821eee32000-10-25 17:59:17 +0000273
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000274class Expression(Node):
275 # Expression is an artificial node class to support "eval"
276 nodes["expression"] = "Expression"
277 def __init__(self, node):
278 self.node = node
279
280 def getChildren(self):
281 return self.node,
282
283 def getChildNodes(self):
284 return self.node,
285
286 def __repr__(self):
287 return "Expression(%s)" % (repr(self.node))
288
Jeremy Hylton821eee32000-10-25 17:59:17 +0000289### EPILOGUE
Jeremy Hylton566d9342004-09-07 15:28:01 +0000290for name, obj in globals().items():
291 if isinstance(obj, type) and issubclass(obj, Node):
Tim Peters0e9980f2004-09-12 03:49:31 +0000292 nodes[name.lower()] = obj