blob: fc929936cdc14e16f8726e9986518e2b6fcef918 [file] [log] [blame]
Jeremy Hylton821eee32000-10-25 17:59:17 +00001"""Generate ast module from specification"""
2
3import fileinput
4import getopt
5import re
6import sys
7from StringIO import StringIO
8
9SPEC = "ast.txt"
10COMMA = ", "
11
12def load_boilerplate(file):
13 f = open(file)
14 buf = f.read()
15 f.close()
16 i = buf.find('### ''PROLOGUE')
17 j = buf.find('### ''EPILOGUE')
18 pro = buf[i+12:j].strip()
19 epi = buf[j+12:].strip()
20 return pro, epi
21
22def strip_default(arg):
23 """Return the argname from an 'arg = default' string"""
24 i = arg.find('=')
25 if i == -1:
26 return arg
27 return arg[:i].strip()
28
29class NodeInfo:
30 """Each instance describes a specific AST node"""
31 def __init__(self, name, args):
32 self.name = name
33 self.args = args.strip()
34 self.argnames = self.get_argnames()
35 self.nargs = len(self.argnames)
36 self.children = COMMA.join(["self.%s" % c
37 for c in self.argnames])
38 self.init = []
39
40 def get_argnames(self):
41 if '(' in self.args:
42 i = self.args.find('(')
43 j = self.args.rfind(')')
44 args = self.args[i+1:j]
45 else:
46 args = self.args
47 return [strip_default(arg.strip())
48 for arg in args.split(',') if arg]
49
50 def gen_source(self):
51 buf = StringIO()
52 print >> buf, "class %s(Node):" % self.name
53 print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
54 self._gen_init(buf)
55 self._gen_getChildren(buf)
56 self._gen_repr(buf)
57 buf.seek(0, 0)
58 return buf.read()
59
60 def _gen_init(self, buf):
61 print >> buf, " def __init__(self, %s):" % self.args
62 if self.argnames:
63 for name in self.argnames:
64 print >> buf, " self.%s = %s" % (name, name)
65 else:
66 print >> buf, " pass"
67 if self.init:
68 print >> buf, "".join([" " + line for line in self.init])
69
70 def _gen_getChildren(self, buf):
71 print >> buf, " def _getChildren(self):"
72 if self.argnames:
73 if self.nargs == 1:
74 print >> buf, " return %s," % self.children
75 else:
76 print >> buf, " return %s" % self.children
77 else:
78 print >> buf, " return ()"
79
80 def _gen_repr(self, buf):
81 print >> buf, " def __repr__(self):"
82 if self.argnames:
83 fmt = COMMA.join(["%s"] * self.nargs)
84 vals = ["repr(self.%s)" % name for name in self.argnames]
85 vals = COMMA.join(vals)
86 if self.nargs == 1:
87 vals = vals + ","
88 print >> buf, ' return "%s(%s)" %% (%s)' % \
89 (self.name, fmt, vals)
90 else:
91 print >> buf, ' return "%s()"' % self.name
92
93rx_init = re.compile('init\((.*)\):')
94
95def parse_spec(file):
96 classes = {}
97 cur = None
98 for line in fileinput.input(file):
99 mo = rx_init.search(line)
100 if mo is None:
101 if cur is None:
102 # a normal entry
103 try:
104 name, args = line.split(':')
105 except ValueError:
106 continue
107 classes[name] = NodeInfo(name, args)
108 cur = None
109 else:
110 # some code for the __init__ method
111 cur.init.append(line)
112 else:
113 # some extra code for a Node's __init__ method
114 name = mo.group(1)
115 cur = classes[name]
116 return classes.values()
117
118def main():
119 prologue, epilogue = load_boilerplate(sys.argv[-1])
120 print prologue
121 print
122 classes = parse_spec(SPEC)
123 for info in classes:
124 print info.gen_source()
125 print epilogue
126
127if __name__ == "__main__":
128 main()
129 sys.exit(0)
130
131### PROLOGUE
132"""Python abstract syntax node definitions
133
134This file is automatically generated.
135"""
136from types import TupleType, ListType
137from consts import CO_VARARGS, CO_VARKEYWORDS
138
139def flatten(list):
140 l = []
141 for elt in list:
142 t = type(elt)
143 if t is TupleType or t is ListType:
144 for elt2 in flatten(elt):
145 l.append(elt2)
146 else:
147 l.append(elt)
148 return l
149
150def asList(nodes):
151 l = []
152 for item in nodes:
153 if hasattr(item, "asList"):
154 l.append(item.asList())
155 else:
156 t = type(item)
157 if t is TupleType or t is ListType:
158 l.append(tuple(asList(item)))
159 else:
160 l.append(item)
161 return l
162
163nodes = {}
164
165class Node:
166 lineno = None
167 def getType(self):
168 pass
169 def getChildren(self):
170 # XXX It would be better to generate flat values to begin with
171 return flatten(self._getChildren())
172 def asList(self):
173 return tuple(asList(self.getChildren()))
Jeremy Hyltoneef65902001-08-14 18:58:00 +0000174 def getChildNodes(self):
175 return [n for n in self.getChildnre() if isinstance(n, Node)]
Jeremy Hylton821eee32000-10-25 17:59:17 +0000176
177class EmptyNode(Node):
178 def __init__(self):
179 self.lineno = None
180
181### EPILOGUE
182klasses = globals()
183for k in nodes.keys():
184 nodes[k] = klasses[nodes[k]]