blob: 4ccc54d638565941a834d441b8a0e95d25f10894 [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()
96 print >> buf, "class %s(Node):" % self.name
Jeremy Hylton821eee32000-10-25 17:59:17 +000097 self._gen_init(buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +000098 print >> buf
Jeremy Hylton821eee32000-10-25 17:59:17 +000099 self._gen_getChildren(buf)
Jeremy Hylton5477f522001-08-29 18:08:02 +0000100 print >> buf
101 self._gen_getChildNodes(buf)
102 print >> 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:
109 print >> buf, " def __init__(self, %s, lineno=None):" % self.args
110 else:
111 print >> buf, " def __init__(self, lineno=None):"
Jeremy Hylton821eee32000-10-25 17:59:17 +0000112 if self.argnames:
113 for name in self.argnames:
114 print >> buf, " self.%s = %s" % (name, name)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000115 print >> buf, " self.lineno = lineno"
Jeremy Hylton821eee32000-10-25 17:59:17 +0000116 if self.init:
117 print >> buf, "".join([" " + line for line in self.init])
118
119 def _gen_getChildren(self, buf):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000120 print >> buf, " def getChildren(self):"
121 if len(self.argnames) == 0:
Jeremy Hylton821eee32000-10-25 17:59:17 +0000122 print >> buf, " return ()"
Jeremy Hylton5477f522001-08-29 18:08:02 +0000123 else:
124 if self.hardest_arg < P_NESTED:
125 clist = COMMA.join(["self.%s" % c
126 for c in self.argnames])
127 if self.nargs == 1:
128 print >> buf, " return %s," % clist
129 else:
130 print >> buf, " return %s" % clist
131 else:
Jeremy Hylton566d9342004-09-07 15:28:01 +0000132 if len(self.argnames) == 1:
133 print >> buf, " return tuple(flatten(self.%s))" % self.argnames[0]
134 else:
135 print >> buf, " children = []"
136 template = " children.%s(%sself.%s%s)"
137 for name in self.argnames:
138 if self.argprops[name] == P_NESTED:
139 print >> buf, template % ("extend", "flatten(",
140 name, ")")
141 else:
142 print >> buf, template % ("append", "", name, "")
143 print >> buf, " return tuple(children)"
Jeremy Hylton5477f522001-08-29 18:08:02 +0000144
145 def _gen_getChildNodes(self, buf):
146 print >> buf, " def getChildNodes(self):"
147 if len(self.argnames) == 0:
148 print >> buf, " return ()"
149 else:
150 if self.hardest_arg < P_NESTED:
151 clist = ["self.%s" % c
152 for c in self.argnames
153 if self.argprops[c] == P_NODE]
154 if len(clist) == 0:
155 print >> buf, " return ()"
156 elif len(clist) == 1:
157 print >> buf, " return %s," % clist[0]
158 else:
159 print >> buf, " return %s" % COMMA.join(clist)
160 else:
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000161 print >> buf, " nodelist = []"
162 template = " nodelist.%s(%sself.%s%s)"
Jeremy Hylton5477f522001-08-29 18:08:02 +0000163 for name in self.argnames:
164 if self.argprops[name] == P_NONE:
Jeremy Hylton566d9342004-09-07 15:28:01 +0000165 tmp = (" if self.%s is not None:\n"
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000166 " nodelist.append(self.%s)")
Jeremy Hylton5477f522001-08-29 18:08:02 +0000167 print >> buf, tmp % (name, name)
168 elif self.argprops[name] == P_NESTED:
169 print >> buf, template % ("extend", "flatten_nodes(",
170 name, ")")
171 elif self.argprops[name] == P_NODE:
172 print >> buf, template % ("append", "", name, "")
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000173 print >> buf, " return tuple(nodelist)"
Jeremy Hylton821eee32000-10-25 17:59:17 +0000174
175 def _gen_repr(self, buf):
176 print >> buf, " def __repr__(self):"
177 if self.argnames:
178 fmt = COMMA.join(["%s"] * self.nargs)
Jeremy Hyltonab427b82001-08-18 00:14:37 +0000179 if '(' in self.args:
180 fmt = '(%s)' % fmt
Jeremy Hylton821eee32000-10-25 17:59:17 +0000181 vals = ["repr(self.%s)" % name for name in self.argnames]
182 vals = COMMA.join(vals)
183 if self.nargs == 1:
184 vals = vals + ","
185 print >> buf, ' return "%s(%s)" %% (%s)' % \
186 (self.name, fmt, vals)
187 else:
188 print >> buf, ' return "%s()"' % self.name
189
190rx_init = re.compile('init\((.*)\):')
191
192def parse_spec(file):
193 classes = {}
194 cur = None
195 for line in fileinput.input(file):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000196 if line.strip().startswith('#'):
197 continue
Jeremy Hylton821eee32000-10-25 17:59:17 +0000198 mo = rx_init.search(line)
199 if mo is None:
200 if cur is None:
201 # a normal entry
202 try:
203 name, args = line.split(':')
204 except ValueError:
205 continue
206 classes[name] = NodeInfo(name, args)
207 cur = None
208 else:
209 # some code for the __init__ method
210 cur.init.append(line)
211 else:
212 # some extra code for a Node's __init__ method
213 name = mo.group(1)
214 cur = classes[name]
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000215 return sorted(classes.values(), key=lambda n: n.name)
Jeremy Hylton821eee32000-10-25 17:59:17 +0000216
217def main():
218 prologue, epilogue = load_boilerplate(sys.argv[-1])
219 print prologue
220 print
221 classes = parse_spec(SPEC)
222 for info in classes:
223 print info.gen_source()
224 print epilogue
225
226if __name__ == "__main__":
227 main()
228 sys.exit(0)
229
230### PROLOGUE
231"""Python abstract syntax node definitions
232
Jeremy Hylton566d9342004-09-07 15:28:01 +0000233This file is automatically generated by Tools/compiler/astgen.py
Jeremy Hylton821eee32000-10-25 17:59:17 +0000234"""
Jeremy Hylton821eee32000-10-25 17:59:17 +0000235from consts import CO_VARARGS, CO_VARKEYWORDS
236
237def flatten(list):
238 l = []
239 for elt in list:
240 t = type(elt)
Jeremy Hylton566d9342004-09-07 15:28:01 +0000241 if t is tuple or t is list:
Jeremy Hylton821eee32000-10-25 17:59:17 +0000242 for elt2 in flatten(elt):
243 l.append(elt2)
244 else:
245 l.append(elt)
246 return l
247
Jeremy Hylton5477f522001-08-29 18:08:02 +0000248def flatten_nodes(list):
249 return [n for n in flatten(list) if isinstance(n, Node)]
250
Jeremy Hylton821eee32000-10-25 17:59:17 +0000251nodes = {}
252
Jeremy Hylton566d9342004-09-07 15:28:01 +0000253class Node:
254 """Abstract base class for ast nodes."""
Jeremy Hylton821eee32000-10-25 17:59:17 +0000255 def getChildren(self):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000256 pass # implemented by subclasses
Jeremy Hylton566d9342004-09-07 15:28:01 +0000257 def __iter__(self):
258 for n in self.getChildren():
259 yield n
260 def asList(self): # for backwards compatibility
261 return self.getChildren()
Jeremy Hyltoneef65902001-08-14 18:58:00 +0000262 def getChildNodes(self):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000263 pass # implemented by subclasses
Jeremy Hylton821eee32000-10-25 17:59:17 +0000264
265class EmptyNode(Node):
Jeremy Hylton5477f522001-08-29 18:08:02 +0000266 pass
Jeremy Hylton821eee32000-10-25 17:59:17 +0000267
Anthony Baxterc2a5a632004-08-02 06:10:11 +0000268class Expression(Node):
269 # Expression is an artificial node class to support "eval"
270 nodes["expression"] = "Expression"
271 def __init__(self, node):
272 self.node = node
273
274 def getChildren(self):
275 return self.node,
276
277 def getChildNodes(self):
278 return self.node,
279
280 def __repr__(self):
281 return "Expression(%s)" % (repr(self.node))
282
Jeremy Hylton821eee32000-10-25 17:59:17 +0000283### EPILOGUE
Jeremy Hylton566d9342004-09-07 15:28:01 +0000284for name, obj in globals().items():
285 if isinstance(obj, type) and issubclass(obj, Node):
Tim Peters0e9980f2004-09-12 03:49:31 +0000286 nodes[name.lower()] = obj