# HG changeset patch # User Paul Boddie # Date 1341525111 -7200 # Node ID e9b25a4d49038ee9c95eb522cb5263fc3ab20a8b # Parent 39f7dc0698c4ade0735c339483087f636b274d30 Added string "display" representations for the nodes, allowing ASTs to be printed and appear as source code. diff -r 39f7dc0698c4 -r e9b25a4d4903 compiler/ast.py --- a/compiler/ast.py Tue Jun 12 00:20:29 2012 +0200 +++ b/compiler/ast.py Thu Jul 05 23:51:51 2012 +0200 @@ -18,6 +18,26 @@ def flatten_nodes(seq): return [n for n in flatten(seq) if isinstance(n, Node)] +def indent(s): + return s.replace("\n", "\n\t") + +def decode_function(node): + star = (node.flags & 4 != 0) and 1 or 0 + dstar = (node.flags & 8 != 0) and 1 or 0 + argnames = node.argnames[:] + + # Add stars to star and dstar parameters. + + if star: + argnames[-dstar-star] = "*%s" % argnames[-dstar-star] + if dstar: + argnames[-dstar] = "**%s" % argnames[-dstar] + + # Map defaults to parameters. + + defaults = [None] * (len(node.argnames) - star - dstar - len(node.defaults)) + list(node.defaults) + [None] * (star + dstar) + return [(default and "%s=%s" % (argname, default) or argname) for (argname, default) in zip(argnames, defaults)] + nodes = {} class Node: @@ -52,6 +72,9 @@ def __repr__(self): return "Expression(%r)" % (self.node,) + def __str__(self): + return str(self.node) + def visit(self, visitor, *args): return visitor.visitExpression(self, *args) @@ -70,6 +93,9 @@ def __repr__(self): return "Add((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s + %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitAdd(self, *args) @@ -89,6 +115,9 @@ def __repr__(self): return "And(%r)" % (self.nodes,) + def __str__(self): + return " and ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitAnd(self, *args) @@ -108,6 +137,9 @@ def __repr__(self): return "AssAttr(%r, %r, %r)" % (self.expr, self.attrname, self.flags) + def __str__(self): + return "%s.%s" % (self.expr, self.attrname) # NOTE: self.flags not used + def visit(self, visitor, *args): return visitor.visitAssAttr(self, *args) @@ -127,6 +159,9 @@ def __repr__(self): return "AssList(%r)" % (self.nodes,) + def __str__(self): + return "[%s]" % ", ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitAssList(self, *args) @@ -145,6 +180,9 @@ def __repr__(self): return "AssName(%r, %r)" % (self.name, self.flags) + def __str__(self): + return str(self.name) # NOTE: self.flags not used + def visit(self, visitor, *args): return visitor.visitAssName(self, *args) @@ -164,6 +202,9 @@ def __repr__(self): return "AssTuple(%r)" % (self.nodes,) + def __str__(self): + return "(%s)" % ", ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitAssTuple(self, *args) @@ -189,6 +230,9 @@ def __repr__(self): return "Assert(%r, %r)" % (self.test, self.fail) + def __str__(self): + return "assert %s%s" % (self.test, self.fail and ", %s" % self.fail or "") + def visit(self, visitor, *args): return visitor.visitAssert(self, *args) @@ -213,6 +257,9 @@ def __repr__(self): return "Assign(%r, %r)" % (self.nodes, self.expr) + def __str__(self): + return "%s = %s" % (", ".join(map(str, self.nodes)), self.expr) + def visit(self, visitor, *args): return visitor.visitAssign(self, *args) @@ -232,6 +279,9 @@ def __repr__(self): return "AugAssign(%r, %r, %r)" % (self.node, self.op, self.expr) + def __str__(self): + return "%s %s %s" % (self.node, self.op, self.expr) + def visit(self, visitor, *args): return visitor.visitAugAssign(self, *args) @@ -249,6 +299,9 @@ def __repr__(self): return "Backquote(%r)" % (self.expr,) + def __str__(self): + return "`%s`" % self.expr + def visit(self, visitor, *args): return visitor.visitBackquote(self, *args) @@ -268,6 +321,9 @@ def __repr__(self): return "Bitand(%r)" % (self.nodes,) + def __str__(self): + return " & ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitBitand(self, *args) @@ -287,6 +343,9 @@ def __repr__(self): return "Bitor(%r)" % (self.nodes,) + def __str__(self): + return " | ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitBitor(self, *args) @@ -306,6 +365,9 @@ def __repr__(self): return "Bitxor(%r)" % (self.nodes,) + def __str__(self): + return " ^ ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitBitxor(self, *args) @@ -322,6 +384,9 @@ def __repr__(self): return "Break()" + def __str__(self): + return "break" + def visit(self, visitor, *args): return visitor.visitBreak(self, *args) @@ -354,6 +419,11 @@ def __repr__(self): return "CallFunc(%r, %r, %r, %r)" % (self.node, self.args, self.star_args, self.dstar_args) + def __str__(self): + star_args = self.star_args and ["*%s" % self.star_args] or [] + dstar_args = self.dstar_args and ["**%s" % self.dstar_args] or [] + return "%s(%s)" % (self.node, ", ".join(map(str, self.args + star_args + dstar_args))) + def visit(self, visitor, *args): return visitor.visitCallFunc(self, *args) @@ -382,6 +452,15 @@ def __repr__(self): return "Class(%r, %r, %r, %r)" % (self.name, self.bases, self.doc, self.code) + def __str__(self): + return "%sclass %s%s:%s%s" % ( + self.decorators and "%s\n" % "\n".join([("@%s" % decorator) for decorator in self.decorators]) or "", + self.name, + self.bases and "(%s)" % ", ".join(map(str, self.bases)) or "", + indent(self.doc and "\n%r" % self.doc or ""), + indent("\n%s" % self.code) + ) + def visit(self, visitor, *args): return visitor.visitClass(self, *args) @@ -406,6 +485,9 @@ def __repr__(self): return "Compare(%r, %r)" % (self.expr, self.ops) + def __str__(self): + return "%s %s" % (self.expr, " ".join([("%s %s" % op) for op in self.ops])) + def visit(self, visitor, *args): return visitor.visitCompare(self, *args) @@ -423,6 +505,9 @@ def __repr__(self): return "Const(%r)" % (self.value,) + def __str__(self): + return repr(self.value) + def visit(self, visitor, *args): return visitor.visitConst(self, *args) @@ -439,6 +524,9 @@ def __repr__(self): return "Continue()" + def __str__(self): + return "continue" + def visit(self, visitor, *args): return visitor.visitContinue(self, *args) @@ -458,6 +546,9 @@ def __repr__(self): return "Decorators(%r)" % (self.nodes,) + def __str__(self): + return "\n".join([("@%s" % node) for node in self.nodes]) + def visit(self, visitor, *args): return visitor.visitDecorators(self, *args) @@ -477,6 +568,9 @@ def __repr__(self): return "Dict(%r)" % (self.items,) + def __str__(self): + return "{%s}" % ", ".join(map(str, self.items)) + def visit(self, visitor, *args): return visitor.visitDict(self, *args) @@ -494,6 +588,9 @@ def __repr__(self): return "Discard(%r)" % (self.expr,) + def __str__(self): + return str(self.expr) + def visit(self, visitor, *args): return visitor.visitDiscard(self, *args) @@ -512,6 +609,9 @@ def __repr__(self): return "Div((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s / %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitDiv(self, *args) @@ -528,6 +628,9 @@ def __repr__(self): return "Ellipsis()" + def __str__(self): + return "..." + def visit(self, visitor, *args): return visitor.visitEllipsis(self, *args) @@ -557,6 +660,10 @@ def __repr__(self): return "Exec(%r, %r, %r)" % (self.expr, self.locals, self.globals) + def __str__(self): + return "exec %s%s%s" % (self.expr, self.locals and ", %s" % self.locals or "", + self.globals and ", %s" % self.globals or "") + def visit(self, visitor, *args): return visitor.visitExec(self, *args) @@ -575,6 +682,9 @@ def __repr__(self): return "FloorDiv((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s // %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitFloorDiv(self, *args) @@ -606,6 +716,13 @@ def __repr__(self): return "For(%r, %r, %r, %r)" % (self.assign, self.list, self.body, self.else_) + def __str__(self): + return "for %s in %s:%s%s" % ( + self.assign, self.list, + indent("\n%s" % self.body), + self.else_ and "\nelse:%s" % indent("\n%s" % self.else_) or "" + ) + def visit(self, visitor, *args): return visitor.visitFor(self, *args) @@ -625,6 +742,10 @@ def __repr__(self): return "From(%r, %r, %r)" % (self.modname, self.names, self.level) + def __str__(self): + return "from %s import %s" % (self.modname, + ", ".join([(alias and "%s as %s" % (name, alias) or name) for (name, alias) in self.names])) + def visit(self, visitor, *args): return visitor.visitFrom(self, *args) @@ -644,8 +765,6 @@ if flags & CO_VARKEYWORDS: self.kwargs = 1 - - def getChildren(self): children = [] children.append(self.decorators) @@ -668,6 +787,17 @@ def __repr__(self): return "Function(%r, %r, %r, %r, %r, %r, %r)" % (self.decorators, self.name, self.argnames, self.defaults, self.flags, self.doc, self.code) + def __str__(self): + parameters = decode_function(self) + + return "%sdef %s(%s):%s%s" % ( + self.decorators and "%s\n" % "\n".join([("@%s" % decorator) for decorator in self.decorators]) or "", + self.name, + ", ".join(parameters), + indent(self.doc and "\n%r" % self.doc or ""), + indent("\n%s" % self.code) + ) + def visit(self, visitor, *args): return visitor.visitFunction(self, *args) @@ -687,6 +817,9 @@ def __repr__(self): return "GenExpr(%r)" % (self.code,) + def __str__(self): + return str(self.code) + def visit(self, visitor, *args): return visitor.visitGenExpr(self, *args) @@ -698,7 +831,6 @@ self.lineno = lineno self.is_outmost = False - def getChildren(self): children = [] children.append(self.assign) @@ -716,6 +848,12 @@ def __repr__(self): return "GenExprFor(%r, %r, %r)" % (self.assign, self.iter, self.ifs) + def __str__(self): + return "for %s in %s%s" % ( + self.assign, self.iter, + self.ifs and " ".join(map(str, self.ifs)) or "" + ) + def visit(self, visitor, *args): return visitor.visitGenExprFor(self, *args) @@ -733,6 +871,9 @@ def __repr__(self): return "GenExprIf(%r)" % (self.test,) + def __str__(self): + return "if %s" % self.test + def visit(self, visitor, *args): return visitor.visitGenExprIf(self, *args) @@ -757,6 +898,9 @@ def __repr__(self): return "GenExprInner(%r, %r)" % (self.expr, self.quals) + def __str__(self): + return "%s %s" % (self.expr, " ".join(map(str, self.quals))) + def visit(self, visitor, *args): return visitor.visitGenExprInner(self, *args) @@ -775,6 +919,9 @@ def __repr__(self): return "Getattr(%r, %r)" % (self.expr, self.attrname) + def __str__(self): + return "%s.%s" % (self.expr, self.attrname) + def visit(self, visitor, *args): return visitor.visitGetattr(self, *args) @@ -792,6 +939,9 @@ def __repr__(self): return "Global(%r)" % (self.names,) + def __str__(self): + return "global %s" % ", ".join(map(str, self.names)) + def visit(self, visitor, *args): return visitor.visitGlobal(self, *args) @@ -817,6 +967,13 @@ def __repr__(self): return "If(%r, %r)" % (self.tests, self.else_) + def __str__(self): + tests = [("%sif %s:%s" % (i > 0 and "el" or "", test, indent("\n%s" % body))) for (i, (test, body)) in enumerate(self.tests)] + return "%s%s" % ( + "\n".join(tests), + self.else_ and "\nelse:%s" % indent("\n%s" % self.else_) or "" + ) + def visit(self, visitor, *args): return visitor.visitIf(self, *args) @@ -836,6 +993,9 @@ def __repr__(self): return "IfExp(%r, %r, %r)" % (self.test, self.then, self.else_) + def __str__(self): + return "%s if %s else %s" % (self.then, self.test, self.else_) + def visit(self, visitor, *args): return visitor.visitIfExp(self, *args) @@ -853,6 +1013,10 @@ def __repr__(self): return "Import(%r)" % (self.names,) + def __str__(self): + return "import %s" % ( + ", ".join([(alias and "%s as %s" % (name, alias) or name) for (name, alias) in self.names])) + def visit(self, visitor, *args): return visitor.visitImport(self, *args) @@ -870,6 +1034,9 @@ def __repr__(self): return "Invert(%r)" % (self.expr,) + def __str__(self): + return "~%s" % self.expr + def visit(self, visitor, *args): return visitor.visitInvert(self, *args) @@ -888,6 +1055,9 @@ def __repr__(self): return "Keyword(%r, %r)" % (self.name, self.expr) + def __str__(self): + return "%s=%s" % (self.name, self.expr) + def visit(self, visitor, *args): return visitor.visitKeyword(self, *args) @@ -923,6 +1093,10 @@ def __repr__(self): return "Lambda(%r, %r, %r, %r)" % (self.argnames, self.defaults, self.flags, self.code) + def __str__(self): + parameters = decode_function(self) + return "lambda %s: %s" % (", ".join(parameters), self.code) + def visit(self, visitor, *args): return visitor.visitLambda(self, *args) @@ -941,6 +1115,9 @@ def __repr__(self): return "LeftShift((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s << %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitLeftShift(self, *args) @@ -960,6 +1137,9 @@ def __repr__(self): return "List(%r)" % (self.nodes,) + def __str__(self): + return "[%s]" % ", ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitList(self, *args) @@ -984,6 +1164,9 @@ def __repr__(self): return "ListComp(%r, %r)" % (self.expr, self.quals) + def __str__(self): + return "%s %s" % (self.expr, " ".join(map(str, self.quals))) + def visit(self, visitor, *args): return visitor.visitListComp(self, *args) @@ -1011,6 +1194,12 @@ def __repr__(self): return "ListCompFor(%r, %r, %r)" % (self.assign, self.list, self.ifs) + def __str__(self): + return "for %s in %s%s" % ( + self.assign, self.list, + self.ifs and " ".join(map(str, self.ifs)) or "" + ) + def visit(self, visitor, *args): return visitor.visitListCompFor(self, *args) @@ -1028,6 +1217,9 @@ def __repr__(self): return "ListCompIf(%r)" % (self.test,) + def __str__(self): + return "if %s" % self.test + def visit(self, visitor, *args): return visitor.visitListCompIf(self, *args) @@ -1046,6 +1238,9 @@ def __repr__(self): return "Mod((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s %% %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitMod(self, *args) @@ -1064,6 +1259,9 @@ def __repr__(self): return "Module(%r, %r)" % (self.doc, self.node) + def __str__(self): + return "%s%s" % (self.doc and "%r\n" % self.doc or "", self.node) + def visit(self, visitor, *args): return visitor.visitModule(self, *args) @@ -1082,6 +1280,9 @@ def __repr__(self): return "Mul((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s * %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitMul(self, *args) @@ -1099,6 +1300,9 @@ def __repr__(self): return "Name(%r)" % (self.name,) + def __str__(self): + return str(self.name) + def visit(self, visitor, *args): return visitor.visitName(self, *args) @@ -1116,6 +1320,9 @@ def __repr__(self): return "Not(%r)" % (self.expr,) + def __str__(self): + return "not %s" % self.expr + def visit(self, visitor, *args): return visitor.visitNot(self, *args) @@ -1135,6 +1342,9 @@ def __repr__(self): return "Or(%r)" % (self.nodes,) + def __str__(self): + return " or ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitOr(self, *args) @@ -1151,6 +1361,9 @@ def __repr__(self): return "Pass()" + def __str__(self): + return "pass" + def visit(self, visitor, *args): return visitor.visitPass(self, *args) @@ -1169,6 +1382,9 @@ def __repr__(self): return "Power((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s ** %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitPower(self, *args) @@ -1194,6 +1410,10 @@ def __repr__(self): return "Print(%r, %r)" % (self.nodes, self.dest) + def __str__(self): + dest = self.dest and [">>%s" % self.dest] or [] + return "print %s," % ", ".join(map(str, dest + self.nodes)) + def visit(self, visitor, *args): return visitor.visitPrint(self, *args) @@ -1219,6 +1439,10 @@ def __repr__(self): return "Printnl(%r, %r)" % (self.nodes, self.dest) + def __str__(self): + dest = self.dest and [">>%s" % self.dest] or [] + return "print %s" % ", ".join(map(str, dest + self.nodes)) + def visit(self, visitor, *args): return visitor.visitPrintnl(self, *args) @@ -1249,6 +1473,12 @@ def __repr__(self): return "Raise(%r, %r, %r)" % (self.expr1, self.expr2, self.expr3) + def __str__(self): + args = self.expr1 and [self.expr1] or [] + args += self.expr2 and [self.expr2] or [] + args += self.expr3 and [self.expr3] or [] + return "raise %s" % ", ".join(map(str, args)) + def visit(self, visitor, *args): return visitor.visitRaise(self, *args) @@ -1266,6 +1496,9 @@ def __repr__(self): return "Return(%r)" % (self.value,) + def __str__(self): + return "return %s" % self.value + def visit(self, visitor, *args): return visitor.visitReturn(self, *args) @@ -1284,6 +1517,9 @@ def __repr__(self): return "RightShift((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s >> %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitRightShift(self, *args) @@ -1315,6 +1551,12 @@ def __repr__(self): return "Slice(%r, %r, %r, %r)" % (self.expr, self.flags, self.lower, self.upper) + def __str__(self): + args = [] + args = self.lower is not None and [self.lower] or [] + args = self.upper is not None and [self.upper] or [] + return "%s[%s]" % (self.expr, ":".join(map(str, args))) + def visit(self, visitor, *args): return visitor.visitSlice(self, *args) @@ -1334,6 +1576,9 @@ def __repr__(self): return "Sliceobj(%r)" % (self.nodes,) + def __str__(self): + return ":".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitSliceobj(self, *args) @@ -1353,6 +1598,9 @@ def __repr__(self): return "Stmt(%r)" % (self.nodes,) + def __str__(self): + return "\n".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitStmt(self, *args) @@ -1371,6 +1619,9 @@ def __repr__(self): return "Sub((%r, %r))" % (self.left, self.right) + def __str__(self): + return "%s - %s" % (self.left, self.right) + def visit(self, visitor, *args): return visitor.visitSub(self, *args) @@ -1397,6 +1648,9 @@ def __repr__(self): return "Subscript(%r, %r, %r)" % (self.expr, self.flags, self.subs) + def __str__(self): + return "%s[%s]" % (self.expr, ",".join(map(str, self.subs))) + def visit(self, visitor, *args): return visitor.visitSubscript(self, *args) @@ -1425,6 +1679,18 @@ def __repr__(self): return "TryExcept(%r, %r, %r)" % (self.body, self.handlers, self.else_) + def __str__(self): + handlers = [ + ("\nexcept%s%s:%s" % (spec and " %s" % spec or "", assign and ", %s" % assign or "", indent("\n%s" % statement))) + for (spec, assign, statement) in self.handlers + ] + + return "try:%s%s%s" % ( + indent("\n%s" % self.body), + "".join(handlers), + self.else_ and "\nelse:%s" % indent("\n%s" % self.else_) or "" + ) + def visit(self, visitor, *args): return visitor.visitTryExcept(self, *args) @@ -1443,6 +1709,12 @@ def __repr__(self): return "TryFinally(%r, %r)" % (self.body, self.final) + def __str__(self): + return "try:%s\nfinally:%s" % ( + indent("\n%s" % self.body), + indent("\n%s" % self.final) + ) + def visit(self, visitor, *args): return visitor.visitTryFinally(self, *args) @@ -1462,6 +1734,9 @@ def __repr__(self): return "Tuple(%r)" % (self.nodes,) + def __str__(self): + return "(%s)" % ", ".join(map(str, self.nodes)) + def visit(self, visitor, *args): return visitor.visitTuple(self, *args) @@ -1479,6 +1754,9 @@ def __repr__(self): return "UnaryAdd(%r)" % (self.expr,) + def __str__(self): + return "+%s" % self.expr + def visit(self, visitor, *args): return visitor.visitUnaryAdd(self, *args) @@ -1496,6 +1774,9 @@ def __repr__(self): return "UnarySub(%r)" % (self.expr,) + def __str__(self): + return "-%s" % self.expr + def visit(self, visitor, *args): return visitor.visitUnarySub(self, *args) @@ -1524,6 +1805,13 @@ def __repr__(self): return "While(%r, %r, %r)" % (self.test, self.body, self.else_) + def __str__(self): + return "while %s:%s%s" % ( + self.test, + indent("\n%s" % self.body), + self.else_ and "\nelse:%s" % indent("\n%s" % self.else_) or "" + ) + def visit(self, visitor, *args): return visitor.visitWhile(self, *args) @@ -1552,6 +1840,13 @@ def __repr__(self): return "With(%r, %r, %r)" % (self.expr, self.vars, self.body) + def __str__(self): + return "with %s%s:%s" % ( + self.expr, + self.vars and " as %s" % ", ".join(map(str, self.vars)), + indent("\n%s" % self.body), + ) + def visit(self, visitor, *args): return visitor.visitWith(self, *args) @@ -1569,6 +1864,9 @@ def __repr__(self): return "Yield(%r)" % (self.value,) + def __str__(self): + return "yield %s" % self.value + def visit(self, visitor, *args): return visitor.visitYield(self, *args)