blob: c0eb464a6291bcb7eba8dc3982274763185f98db [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)
Jeremy Hyltonab427b82001-08-18 00:14:37 +000084 if '(' in self.args:
85 fmt = '(%s)' % fmt
Jeremy Hylton821eee32000-10-25 17:59:17 +000086 vals = ["repr(self.%s)" % name for name in self.argnames]
87 vals = COMMA.join(vals)
88 if self.nargs == 1:
89 vals = vals + ","
90 print >> buf, ' return "%s(%s)" %% (%s)' % \
91 (self.name, fmt, vals)
92 else:
93 print >> buf, ' return "%s()"' % self.name
94
95rx_init = re.compile('init\((.*)\):')
96
97def parse_spec(file):
98 classes = {}
99 cur = None
100 for line in fileinput.input(file):
101 mo = rx_init.search(line)
102 if mo is None:
103 if cur is None:
104 # a normal entry
105 try:
106 name, args = line.split(':')
107 except ValueError:
108 continue
109 classes[name] = NodeInfo(name, args)
110 cur = None
111 else:
112 # some code for the __init__ method
113 cur.init.append(line)
114 else:
115 # some extra code for a Node's __init__ method
116 name = mo.group(1)
117 cur = classes[name]
118 return classes.values()
119
120def main():
121 prologue, epilogue = load_boilerplate(sys.argv[-1])
122 print prologue
123 print
124 classes = parse_spec(SPEC)
125 for info in classes:
126 print info.gen_source()
127 print epilogue
128
129if __name__ == "__main__":
130 main()
131 sys.exit(0)
132
133### PROLOGUE
134"""Python abstract syntax node definitions
135
136This file is automatically generated.
137"""
138from types import TupleType, ListType
139from consts import CO_VARARGS, CO_VARKEYWORDS
140
141def flatten(list):
142 l = []
143 for elt in list:
144 t = type(elt)
145 if t is TupleType or t is ListType:
146 for elt2 in flatten(elt):
147 l.append(elt2)
148 else:
149 l.append(elt)
150 return l
151
152def asList(nodes):
153 l = []
154 for item in nodes:
155 if hasattr(item, "asList"):
156 l.append(item.asList())
157 else:
158 t = type(item)
159 if t is TupleType or t is ListType:
160 l.append(tuple(asList(item)))
161 else:
162 l.append(item)
163 return l
164
165nodes = {}
166
167class Node:
168 lineno = None
169 def getType(self):
170 pass
171 def getChildren(self):
172 # XXX It would be better to generate flat values to begin with
173 return flatten(self._getChildren())
174 def asList(self):
175 return tuple(asList(self.getChildren()))
Jeremy Hyltoneef65902001-08-14 18:58:00 +0000176 def getChildNodes(self):
Jeremy Hylton9272b142001-08-14 21:18:30 +0000177 return [n for n in self.getChildren() if isinstance(n, Node)]
Jeremy Hylton821eee32000-10-25 17:59:17 +0000178
179class EmptyNode(Node):
180 def __init__(self):
181 self.lineno = None
182
183### EPILOGUE
184klasses = globals()
185for k in nodes.keys():
186 nodes[k] = klasses[nodes[k]]