[Python-checkins] CVS: python/dist/src/Tools/compiler/compiler ast.py,1.15,1.16 ast.txt,1.2,1.3 astgen.py,1.4,1.5
Jeremy Hylton
jhylton@users.sourceforge.net
2001年8月29日 11:08:04 -0700
Update of /cvsroot/python/python/dist/src/Tools/compiler/compiler
In directory usw-pr-cvs1:/tmp/cvs-serv13493
Modified Files:
ast.py ast.txt astgen.py
Log Message:
Revise implementations of getChildren() and getChildNodes().
Add support for floor division (// and //=)
The implementation of getChildren() and getChildNodes() is intended to
be faster, because it avoids calling flatten() on every return value.
But it's not clear that it is a lot faster, because constructing a
tuple with just the right values ends up being slow. (Too many
attribute lookups probably.)
The ast.txt file is much more complicated, with funny characters at
the ends of names (*, &, !) to indicate the types of each child node.
The astgen script is also much more complex, making me wonder if it's
still useful.
Index: ast.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/ast.py,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -d -r1.15 -r1.16
*** ast.py 2001年08月18日 00:14:37 1.15
--- ast.py 2001年08月29日 18:08:02 1.16
***************
*** 17,20 ****
--- 17,23 ----
return l
+ def flatten_nodes(list):
+ return [n for n in flatten(list) if isinstance(n, Node)]
+
def asList(nodes):
l = []
***************
*** 32,50 ****
[...1481 lines suppressed...]
self.lower = lower
self.upper = upper
!
! def getChildren(self):
! children = []
! children.append(self.expr)
! children.append(self.flags)
! children.append(self.lower)
! children.append(self.upper)
! return tuple(children)
!
! def getChildNodes(self):
! nodes = []
! nodes.append(self.expr)
! if self.lower is not None: nodes.append(self.lower)
! if self.upper is not None: nodes.append(self.upper)
! return tuple(nodes)
!
def __repr__(self):
return "Slice(%s, %s, %s, %s)" % (repr(self.expr), repr(self.flags), repr(self.lower), repr(self.upper))
Index: ast.txt
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/ast.txt,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** ast.txt 2001年08月14日 18:57:43 1.2
--- ast.txt 2001年08月29日 18:08:02 1.3
***************
*** 1,55 ****
! 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
Yield: 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)
--- 1,63 ----
! # This file describes the nodes of the AST in ast.py. The module is
! # generated by astgen.py.
! # The descriptions use the following special notation to describe
! # properties of the children:
! # * this child is not a node
! # ! this child is a sequence that contains nodes in it
! # & this child may be set to None
! # = ... a default value for the node constructor (optional args)
! 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
Yield: 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)
***************
*** 60,63 ****
--- 68,72 ----
Mod: (left, right)
Power: (left, right)
+ FloorDiv: (left, right)
UnaryAdd: expr
UnarySub: expr
Index: astgen.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Tools/compiler/compiler/astgen.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** astgen.py 2001年08月18日 00:14:37 1.4
--- astgen.py 2001年08月29日 18:08:02 1.5
***************
*** 1,3 ****
! """Generate ast module from specification"""
import fileinput
--- 1,10 ----
! """Generate ast module from specification
!
! This script generates the ast module from a simple specification,
! which makes it easy to accomodate changes in the grammar. This
! approach would be quite reasonable if the grammar changed often.
! Instead, it is rather complex to generate the appropriate code. And
! the Node interface has changed more often than the grammar.
! """
import fileinput
***************
*** 25,29 ****
if i == -1:
return arg
! return arg[:i].strip()
class NodeInfo:
--- 32,42 ----
if i == -1:
return arg
! t = arg[:i].strip()
! return t
!
! P_NODE = 1
! P_OTHER = 2
! P_NESTED = 3
! P_NONE = 4
class NodeInfo:
***************
*** 33,39 ****
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 = []
--- 46,51 ----
self.args = args.strip()
self.argnames = self.get_argnames()
+ self.argprops = self.get_argprops()
self.nargs = len(self.argnames)
self.init = []
***************
*** 48,51 ****
--- 60,95 ----
for arg in args.split(',') if arg]
+ def get_argprops(self):
+ """Each argument can have a property like '*' or '!'
+
+ XXX This method modifies the argnames in place!
+ """
+ d = {}
+ hardest_arg = P_NODE
+ for i in range(len(self.argnames)):
+ arg = self.argnames[i]
+ if arg.endswith('*'):
+ arg = self.argnames[i] = arg[:-1]
+ d[arg] = P_OTHER
+ hardest_arg = P_OTHER
+ elif arg.endswith('!'):
+ arg = self.argnames[i] = arg[:-1]
+ d[arg] = P_NESTED
+ hardest_arg = P_NESTED
+ elif arg.endswith('&'):
+ arg = self.argnames[i] = arg[:-1]
+ d[arg] = P_NONE
+ hardest_arg = P_NONE
+ else:
+ d[arg] = P_NODE
+ self.hardest_arg = hardest_arg
+
+ if hardest_arg > P_NODE:
+ self.args = self.args.replace('*', '')
+ self.args = self.args.replace('!', '')
+ self.args = self.args.replace('&', '')
+
+ return d
+
def gen_source(self):
buf = StringIO()
***************
*** 53,57 ****
--- 97,105 ----
print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
self._gen_init(buf)
+ print >> buf
self._gen_getChildren(buf)
+ print >> buf
+ self._gen_getChildNodes(buf)
+ print >> buf
self._gen_repr(buf)
buf.seek(0, 0)
***************
*** 69,80 ****
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):
--- 117,171 ----
def _gen_getChildren(self, buf):
! print >> buf, " def getChildren(self):"
! if len(self.argnames) == 0:
! print >> buf, " return ()"
else:
+ if self.hardest_arg < P_NESTED:
+ clist = COMMA.join(["self.%s" % c
+ for c in self.argnames])
+ if self.nargs == 1:
+ print >> buf, " return %s," % clist
+ else:
+ print >> buf, " return %s" % clist
+ else:
+ print >> buf, " children = []"
+ template = " children.%s(%sself.%s%s)"
+ for name in self.argnames:
+ if self.argprops[name] == P_NESTED:
+ print >> buf, template % ("extend", "flatten(",
+ name, ")")
+ else:
+ print >> buf, template % ("append", "", name, "")
+ print >> buf, " return tuple(children)"
+
+ def _gen_getChildNodes(self, buf):
+ print >> buf, " def getChildNodes(self):"
+ if len(self.argnames) == 0:
print >> buf, " return ()"
+ else:
+ if self.hardest_arg < P_NESTED:
+ clist = ["self.%s" % c
+ for c in self.argnames
+ if self.argprops[c] == P_NODE]
+ if len(clist) == 0:
+ print >> buf, " return ()"
+ elif len(clist) == 1:
+ print >> buf, " return %s," % clist[0]
+ else:
+ print >> buf, " return %s" % COMMA.join(clist)
+ else:
+ print >> buf, " nodes = []"
+ template = " nodes.%s(%sself.%s%s)"
+ for name in self.argnames:
+ if self.argprops[name] == P_NONE:
+ tmp = (" if self.%s is not None:"
+ " nodes.append(self.%s)")
+ print >> buf, tmp % (name, name)
+ elif self.argprops[name] == P_NESTED:
+ print >> buf, template % ("extend", "flatten_nodes(",
+ name, ")")
+ elif self.argprops[name] == P_NODE:
+ print >> buf, template % ("append", "", name, "")
+ print >> buf, " return tuple(nodes)"
def _gen_repr(self, buf):
***************
*** 99,102 ****
--- 190,195 ----
cur = None
for line in fileinput.input(file):
+ if line.strip().startswith('#'):
+ continue
mo = rx_init.search(line)
if mo is None:
***************
*** 150,153 ****
--- 243,249 ----
return l
+ def flatten_nodes(list):
+ return [n for n in flatten(list) if isinstance(n, Node)]
+
def asList(nodes):
l = []
***************
*** 165,183 ****
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()))
def getChildNodes(self):
! return [n for n in self.getChildren() if isinstance(n, Node)]
class EmptyNode(Node):
! def __init__(self):
! self.lineno = None
### EPILOGUE
--- 261,277 ----
nodes = {}
! class Node: # an abstract base class
! lineno = None # provide a lineno for nodes that don't have one
def getType(self):
! pass # implemented by subclass
def getChildren(self):
! pass # implemented by subclasses
def asList(self):
return tuple(asList(self.getChildren()))
def getChildNodes(self):
! pass # implemented by subclasses
class EmptyNode(Node):
! pass
### EPILOGUE