summaryrefslogtreecommitdiffstats
path: root/Tools/compiler
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2000-10-25 17:59:17 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2000-10-25 17:59:17 (GMT)
commit821eee3321f36562e45aa97e25746ad0b6cad31e (patch)
treea294b9507e47122c7c3202f0437fd5608319308f /Tools/compiler
parent6caae14fbd186cf6f677c5b73d68d3c5899bd953 (diff)
downloadcpython-821eee3321f36562e45aa97e25746ad0b6cad31e.zip
cpython-821eee3321f36562e45aa97e25746ad0b6cad31e.tar.gz
cpython-821eee3321f36562e45aa97e25746ad0b6cad31e.tar.bz2
Support for generation of ast.py from simple description of node
structure (ast.txt). Usage is python astgen.py > ast.py.
Diffstat (limited to 'Tools/compiler')
-rw-r--r--Tools/compiler/ast.txt77
-rw-r--r--Tools/compiler/astgen.py182
-rw-r--r--Tools/compiler/compiler/ast.txt77
-rw-r--r--Tools/compiler/compiler/astgen.py182
4 files changed, 518 insertions, 0 deletions
diff --git a/Tools/compiler/ast.txt b/Tools/compiler/ast.txt
new file mode 100644
index 0000000..1ca13f2
--- /dev/null
+++ b/Tools/compiler/ast.txt
@@ -0,0 +1,77 @@
+Module: doc, node
+Stmt: nodes
+Function: name, argnames, defaults, flags, doc, code
+Lambda: argnames, defaults, flags, code
+Class: name, bases, doc, code
+Pass:
+Break:
+Continue:
+For: assign, list, body, else_
+While: test, body, else_
+If: tests, else_
+Exec: expr, locals, globals
+From: modname, names
+Import: names
+Raise: expr1, expr2, expr3
+TryFinally: body, final
+TryExcept: body, handlers, else_
+Return: value
+Const: value
+Print: nodes, dest
+Printnl: nodes, dest
+Discard: expr
+AugAssign: node, op, expr
+Assign: nodes, expr
+AssTuple: nodes
+AssList: nodes
+AssName: name, flags
+AssAttr: expr, attrname, flags
+ListComp: expr, quals
+ListCompFor: assign, list, ifs
+ListCompIf: test
+List: nodes
+Dict: items
+Not: expr
+Compare: expr, ops
+Name: name
+Global: names
+Backquote: expr
+Getattr: expr, attrname
+CallFunc: node, args, star_args = None, dstar_args = None
+Keyword: name, expr
+Subscript: expr, flags, subs
+Ellipsis:
+Sliceobj: nodes
+Slice: expr, flags, lower, upper
+Assert: test, fail
+Tuple: nodes
+Or: nodes
+And: nodes
+Bitor: nodes
+Bitxor: nodes
+Bitand: nodes
+LeftShift: (left, right)
+RightShift: (left, right)
+Add: (left, right)
+Sub: (left, right)
+Mul: (left, right)
+Div: (left, right)
+Mod: (left, right)
+Power: (left, right)
+UnaryAdd: expr
+UnarySub: expr
+Invert: expr
+
+init(Function):
+ self.varargs = self.kwargs = None
+ if flags & CO_VARARGS:
+ self.varargs = 1
+ if flags & CO_VARKEYWORDS:
+ self.kwargs = 1
+
+init(Lambda):
+ self.varargs = self.kwargs = None
+ if flags & CO_VARARGS:
+ self.varargs = 1
+ if flags & CO_VARKEYWORDS:
+ self.kwargs = 1
diff --git a/Tools/compiler/astgen.py b/Tools/compiler/astgen.py
new file mode 100644
index 0000000..c31ca54
--- /dev/null
+++ b/Tools/compiler/astgen.py
@@ -0,0 +1,182 @@
+"""Generate ast module from specification"""
+
+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
+ return arg[:i].strip()
+
+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()
+ self.nargs = len(self.argnames)
+ self.children = COMMA.join(["self.%s" % c
+ for c in 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]
+
+ def gen_source(self):
+ buf = StringIO()
+ print >> buf, "class %s(Node):" % self.name
+ print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
+ self._gen_init(buf)
+ self._gen_getChildren(buf)
+ self._gen_repr(buf)
+ buf.seek(0, 0)
+ return buf.read()
+
+ def _gen_init(self, buf):
+ print >> buf, " def __init__(self, %s):" % self.args
+ if self.argnames:
+ for name in self.argnames:
+ print >> buf, " self.%s = %s" % (name, name)
+ else:
+ print >> buf, " pass"
+ if self.init:
+ print >> buf, "".join([" " + line for line in self.init])
+
+ def _gen_getChildren(self, buf):
+ print >> buf, " def _getChildren(self):"
+ if self.argnames:
+ if self.nargs == 1:
+ print >> buf, " return %s," % self.children
+ else:
+ print >> buf, " return %s" % self.children
+ else:
+ print >> buf, " return ()"
+
+ def _gen_repr(self, buf):
+ print >> buf, " def __repr__(self):"
+ if self.argnames:
+ fmt = COMMA.join(["%s"] * self.nargs)
+ 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):
+ 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]
+ return classes.values()
+
+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
+
+This file is automatically generated.
+"""
+from types import TupleType, ListType
+from consts import CO_VARARGS, CO_VARKEYWORDS
+
+def flatten(list):
+ l = []
+ for elt in list:
+ t = type(elt)
+ if t is TupleType or t is ListType:
+ for elt2 in flatten(elt):
+ l.append(elt2)
+ else:
+ l.append(elt)
+ return l
+
+def asList(nodes):
+ l = []
+ for item in nodes:
+ if hasattr(item, "asList"):
+ l.append(item.asList())
+ else:
+ t = type(item)
+ if t is TupleType or t is ListType:
+ l.append(tuple(asList(item)))
+ else:
+ l.append(item)
+ return l
+
+nodes = {}
+
+class Node:
+ lineno = None
+ def getType(self):
+ pass
+ def getChildren(self):
+ # XXX It would be better to generate flat values to begin with
+ return flatten(self._getChildren())
+ def asList(self):
+ return tuple(asList(self.getChildren()))
+
+class EmptyNode(Node):
+ def __init__(self):
+ self.lineno = None
+
+### EPILOGUE
+klasses = globals()
+for k in nodes.keys():
+ nodes[k] = klasses[nodes[k]]
diff --git a/Tools/compiler/compiler/ast.txt b/Tools/compiler/compiler/ast.txt
new file mode 100644
index 0000000..1ca13f2
--- /dev/null
+++ b/Tools/compiler/compiler/ast.txt
@@ -0,0 +1,77 @@
+Module: doc, node
+Stmt: nodes
+Function: name, argnames, defaults, flags, doc, code
+Lambda: argnames, defaults, flags, code
+Class: name, bases, doc, code
+Pass:
+Break:
+Continue:
+For: assign, list, body, else_
+While: test, body, else_
+If: tests, else_
+Exec: expr, locals, globals
+From: modname, names
+Import: names
+Raise: expr1, expr2, expr3
+TryFinally: body, final
+TryExcept: body, handlers, else_
+Return: value
+Const: value
+Print: nodes, dest
+Printnl: nodes, dest
+Discard: expr
+AugAssign: node, op, expr
+Assign: nodes, expr
+AssTuple: nodes
+AssList: nodes
+AssName: name, flags
+AssAttr: expr, attrname, flags
+ListComp: expr, quals
+ListCompFor: assign, list, ifs
+ListCompIf: test
+List: nodes
+Dict: items
+Not: expr
+Compare: expr, ops
+Name: name
+Global: names
+Backquote: expr
+Getattr: expr, attrname
+CallFunc: node, args, star_args = None, dstar_args = None
+Keyword: name, expr
+Subscript: expr, flags, subs
+Ellipsis:
+Sliceobj: nodes
+Slice: expr, flags, lower, upper
+Assert: test, fail
+Tuple: nodes
+Or: nodes
+And: nodes
+Bitor: nodes
+Bitxor: nodes
+Bitand: nodes
+LeftShift: (left, right)
+RightShift: (left, right)
+Add: (left, right)
+Sub: (left, right)
+Mul: (left, right)
+Div: (left, right)
+Mod: (left, right)
+Power: (left, right)
+UnaryAdd: expr
+UnarySub: expr
+Invert: expr
+
+init(Function):
+ self.varargs = self.kwargs = None
+ if flags & CO_VARARGS:
+ self.varargs = 1
+ if flags & CO_VARKEYWORDS:
+ self.kwargs = 1
+
+init(Lambda):
+ self.varargs = self.kwargs = None
+ if flags & CO_VARARGS:
+ self.varargs = 1
+ if flags & CO_VARKEYWORDS:
+ self.kwargs = 1
diff --git a/Tools/compiler/compiler/astgen.py b/Tools/compiler/compiler/astgen.py
new file mode 100644
index 0000000..c31ca54
--- /dev/null
+++ b/Tools/compiler/compiler/astgen.py
@@ -0,0 +1,182 @@
+"""Generate ast module from specification"""
+
+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
+ return arg[:i].strip()
+
+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()
+ self.nargs = len(self.argnames)
+ self.children = COMMA.join(["self.%s" % c
+ for c in 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]
+
+ def gen_source(self):
+ buf = StringIO()
+ print >> buf, "class %s(Node):" % self.name
+ print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
+ self._gen_init(buf)
+ self._gen_getChildren(buf)
+ self._gen_repr(buf)
+ buf.seek(0, 0)
+ return buf.read()
+
+ def _gen_init(self, buf):
+ print >> buf, " def __init__(self, %s):" % self.args
+ if self.argnames:
+ for name in self.argnames:
+ print >> buf, " self.%s = %s" % (name, name)
+ else:
+ print >> buf, " pass"
+ if self.init:
+ print >> buf, "".join([" " + line for line in self.init])
+
+ def _gen_getChildren(self, buf):
+ print >> buf, " def _getChildren(self):"
+ if self.argnames:
+ if self.nargs == 1:
+ print >> buf, " return %s," % self.children
+ else:
+ print >> buf, " return %s" % self.children
+ else:
+ print >> buf, " return ()"
+
+ def _gen_repr(self, buf):
+ print >> buf, " def __repr__(self):"
+ if self.argnames:
+ fmt = COMMA.join(["%s"] * self.nargs)
+ 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):
+ 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]
+ return classes.values()
+
+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
+
+This file is automatically generated.
+"""
+from types import TupleType, ListType
+from consts import CO_VARARGS, CO_VARKEYWORDS
+
+def flatten(list):
+ l = []
+ for elt in list:
+ t = type(elt)
+ if t is TupleType or t is ListType:
+ for elt2 in flatten(elt):
+ l.append(elt2)
+ else:
+ l.append(elt)
+ return l
+
+def asList(nodes):
+ l = []
+ for item in nodes:
+ if hasattr(item, "asList"):
+ l.append(item.asList())
+ else:
+ t = type(item)
+ if t is TupleType or t is ListType:
+ l.append(tuple(asList(item)))
+ else:
+ l.append(item)
+ return l
+
+nodes = {}
+
+class Node:
+ lineno = None
+ def getType(self):
+ pass
+ def getChildren(self):
+ # XXX It would be better to generate flat values to begin with
+ return flatten(self._getChildren())
+ def asList(self):
+ return tuple(asList(self.getChildren()))
+
+class EmptyNode(Node):
+ def __init__(self):
+ self.lineno = None
+
+### EPILOGUE
+klasses = globals()
+for k in nodes.keys():
+ nodes[k] = klasses[nodes[k]]