mirror of
https://github.com/python/cpython.git
synced 2025-10-15 03:10:29 +00:00
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.
This commit is contained in:
parent
96d68d57be
commit
5477f529d6
6 changed files with 1530 additions and 320 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,56 +1,64 @@
|
||||||
Module: doc, node
|
# This file describes the nodes of the AST in ast.py. The module is
|
||||||
Stmt: nodes
|
# generated by astgen.py.
|
||||||
Function: name, argnames, defaults, flags, doc, code
|
# The descriptions use the following special notation to describe
|
||||||
Lambda: argnames, defaults, flags, code
|
# properties of the children:
|
||||||
Class: name, bases, doc, code
|
# * 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:
|
Pass:
|
||||||
Break:
|
Break:
|
||||||
Continue:
|
Continue:
|
||||||
For: assign, list, body, else_
|
For: assign, list, body, else_&
|
||||||
While: test, body, else_
|
While: test, body, else_&
|
||||||
If: tests, else_
|
If: tests!, else_&
|
||||||
Exec: expr, locals, globals
|
Exec: expr, locals&, globals&
|
||||||
From: modname, names
|
From: modname*, names*
|
||||||
Import: names
|
Import: names*
|
||||||
Raise: expr1, expr2, expr3
|
Raise: expr1&, expr2&, expr3&
|
||||||
TryFinally: body, final
|
TryFinally: body, final
|
||||||
TryExcept: body, handlers, else_
|
TryExcept: body, handlers!, else_&
|
||||||
Return: value
|
Return: value
|
||||||
Yield: value
|
Yield: value
|
||||||
Const: value
|
Const: value*
|
||||||
Print: nodes, dest
|
Print: nodes!, dest&
|
||||||
Printnl: nodes, dest
|
Printnl: nodes!, dest&
|
||||||
Discard: expr
|
Discard: expr
|
||||||
AugAssign: node, op, expr
|
AugAssign: node, op*, expr
|
||||||
Assign: nodes, expr
|
Assign: nodes!, expr
|
||||||
AssTuple: nodes
|
AssTuple: nodes!
|
||||||
AssList: nodes
|
AssList: nodes!
|
||||||
AssName: name, flags
|
AssName: name*, flags*
|
||||||
AssAttr: expr, attrname, flags
|
AssAttr: expr, attrname*, flags*
|
||||||
ListComp: expr, quals
|
ListComp: expr, quals!
|
||||||
ListCompFor: assign, list, ifs
|
ListCompFor: assign, list, ifs!
|
||||||
ListCompIf: test
|
ListCompIf: test
|
||||||
List: nodes
|
List: nodes!
|
||||||
Dict: items
|
Dict: items!
|
||||||
Not: expr
|
Not: expr
|
||||||
Compare: expr, ops
|
Compare: expr, ops!
|
||||||
Name: name
|
Name: name*
|
||||||
Global: names
|
Global: names
|
||||||
Backquote: expr
|
Backquote: expr
|
||||||
Getattr: expr, attrname
|
Getattr: expr, attrname*
|
||||||
CallFunc: node, args, star_args = None, dstar_args = None
|
CallFunc: node, args!, star_args& = None, dstar_args& = None
|
||||||
Keyword: name, expr
|
Keyword: name*, expr
|
||||||
Subscript: expr, flags, subs
|
Subscript: expr, flags*, subs!
|
||||||
Ellipsis:
|
Ellipsis:
|
||||||
Sliceobj: nodes
|
Sliceobj: nodes!
|
||||||
Slice: expr, flags, lower, upper
|
Slice: expr, flags*, lower&, upper&
|
||||||
Assert: test, fail
|
Assert: test, fail&
|
||||||
Tuple: nodes
|
Tuple: nodes!
|
||||||
Or: nodes
|
Or: nodes!
|
||||||
And: nodes
|
And: nodes!
|
||||||
Bitor: nodes
|
Bitor: nodes!
|
||||||
Bitxor: nodes
|
Bitxor: nodes!
|
||||||
Bitand: nodes
|
Bitand: nodes!
|
||||||
LeftShift: (left, right)
|
LeftShift: (left, right)
|
||||||
RightShift: (left, right)
|
RightShift: (left, right)
|
||||||
Add: (left, right)
|
Add: (left, right)
|
||||||
|
@ -59,6 +67,7 @@ Mul: (left, right)
|
||||||
Div: (left, right)
|
Div: (left, right)
|
||||||
Mod: (left, right)
|
Mod: (left, right)
|
||||||
Power: (left, right)
|
Power: (left, right)
|
||||||
|
FloorDiv: (left, right)
|
||||||
UnaryAdd: expr
|
UnaryAdd: expr
|
||||||
UnarySub: expr
|
UnarySub: expr
|
||||||
Invert: expr
|
Invert: expr
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
"""Generate ast module from specification"""
|
"""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
|
import fileinput
|
||||||
import getopt
|
import getopt
|
||||||
|
@ -24,7 +31,13 @@ def strip_default(arg):
|
||||||
i = arg.find('=')
|
i = arg.find('=')
|
||||||
if i == -1:
|
if i == -1:
|
||||||
return arg
|
return arg
|
||||||
return arg[:i].strip()
|
t = arg[:i].strip()
|
||||||
|
return t
|
||||||
|
|
||||||
|
P_NODE = 1
|
||||||
|
P_OTHER = 2
|
||||||
|
P_NESTED = 3
|
||||||
|
P_NONE = 4
|
||||||
|
|
||||||
class NodeInfo:
|
class NodeInfo:
|
||||||
"""Each instance describes a specific AST node"""
|
"""Each instance describes a specific AST node"""
|
||||||
|
@ -32,9 +45,8 @@ class NodeInfo:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.args = args.strip()
|
self.args = args.strip()
|
||||||
self.argnames = self.get_argnames()
|
self.argnames = self.get_argnames()
|
||||||
|
self.argprops = self.get_argprops()
|
||||||
self.nargs = len(self.argnames)
|
self.nargs = len(self.argnames)
|
||||||
self.children = COMMA.join(["self.%s" % c
|
|
||||||
for c in self.argnames])
|
|
||||||
self.init = []
|
self.init = []
|
||||||
|
|
||||||
def get_argnames(self):
|
def get_argnames(self):
|
||||||
|
@ -47,12 +59,48 @@ class NodeInfo:
|
||||||
return [strip_default(arg.strip())
|
return [strip_default(arg.strip())
|
||||||
for arg in args.split(',') if arg]
|
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):
|
def gen_source(self):
|
||||||
buf = StringIO()
|
buf = StringIO()
|
||||||
print >> buf, "class %s(Node):" % self.name
|
print >> buf, "class %s(Node):" % self.name
|
||||||
print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
|
print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
|
||||||
self._gen_init(buf)
|
self._gen_init(buf)
|
||||||
|
print >> buf
|
||||||
self._gen_getChildren(buf)
|
self._gen_getChildren(buf)
|
||||||
|
print >> buf
|
||||||
|
self._gen_getChildNodes(buf)
|
||||||
|
print >> buf
|
||||||
self._gen_repr(buf)
|
self._gen_repr(buf)
|
||||||
buf.seek(0, 0)
|
buf.seek(0, 0)
|
||||||
return buf.read()
|
return buf.read()
|
||||||
|
@ -68,14 +116,57 @@ class NodeInfo:
|
||||||
print >> buf, "".join([" " + line for line in self.init])
|
print >> buf, "".join([" " + line for line in self.init])
|
||||||
|
|
||||||
def _gen_getChildren(self, buf):
|
def _gen_getChildren(self, buf):
|
||||||
print >> buf, " def _getChildren(self):"
|
print >> buf, " def getChildren(self):"
|
||||||
if self.argnames:
|
if len(self.argnames) == 0:
|
||||||
if self.nargs == 1:
|
|
||||||
print >> buf, " return %s," % self.children
|
|
||||||
else:
|
|
||||||
print >> buf, " return %s" % self.children
|
|
||||||
else:
|
|
||||||
print >> buf, " return ()"
|
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):
|
def _gen_repr(self, buf):
|
||||||
print >> buf, " def __repr__(self):"
|
print >> buf, " def __repr__(self):"
|
||||||
|
@ -98,6 +189,8 @@ def parse_spec(file):
|
||||||
classes = {}
|
classes = {}
|
||||||
cur = None
|
cur = None
|
||||||
for line in fileinput.input(file):
|
for line in fileinput.input(file):
|
||||||
|
if line.strip().startswith('#'):
|
||||||
|
continue
|
||||||
mo = rx_init.search(line)
|
mo = rx_init.search(line)
|
||||||
if mo is None:
|
if mo is None:
|
||||||
if cur is None:
|
if cur is None:
|
||||||
|
@ -149,6 +242,9 @@ def flatten(list):
|
||||||
l.append(elt)
|
l.append(elt)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
def flatten_nodes(list):
|
||||||
|
return [n for n in flatten(list) if isinstance(n, Node)]
|
||||||
|
|
||||||
def asList(nodes):
|
def asList(nodes):
|
||||||
l = []
|
l = []
|
||||||
for item in nodes:
|
for item in nodes:
|
||||||
|
@ -164,21 +260,19 @@ def asList(nodes):
|
||||||
|
|
||||||
nodes = {}
|
nodes = {}
|
||||||
|
|
||||||
class Node:
|
class Node: # an abstract base class
|
||||||
lineno = None
|
lineno = None # provide a lineno for nodes that don't have one
|
||||||
def getType(self):
|
def getType(self):
|
||||||
pass
|
pass # implemented by subclass
|
||||||
def getChildren(self):
|
def getChildren(self):
|
||||||
# XXX It would be better to generate flat values to begin with
|
pass # implemented by subclasses
|
||||||
return flatten(self._getChildren())
|
|
||||||
def asList(self):
|
def asList(self):
|
||||||
return tuple(asList(self.getChildren()))
|
return tuple(asList(self.getChildren()))
|
||||||
def getChildNodes(self):
|
def getChildNodes(self):
|
||||||
return [n for n in self.getChildren() if isinstance(n, Node)]
|
pass # implemented by subclasses
|
||||||
|
|
||||||
class EmptyNode(Node):
|
class EmptyNode(Node):
|
||||||
def __init__(self):
|
pass
|
||||||
self.lineno = None
|
|
||||||
|
|
||||||
### EPILOGUE
|
### EPILOGUE
|
||||||
klasses = globals()
|
klasses = globals()
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,56 +1,64 @@
|
||||||
Module: doc, node
|
# This file describes the nodes of the AST in ast.py. The module is
|
||||||
Stmt: nodes
|
# generated by astgen.py.
|
||||||
Function: name, argnames, defaults, flags, doc, code
|
# The descriptions use the following special notation to describe
|
||||||
Lambda: argnames, defaults, flags, code
|
# properties of the children:
|
||||||
Class: name, bases, doc, code
|
# * 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:
|
Pass:
|
||||||
Break:
|
Break:
|
||||||
Continue:
|
Continue:
|
||||||
For: assign, list, body, else_
|
For: assign, list, body, else_&
|
||||||
While: test, body, else_
|
While: test, body, else_&
|
||||||
If: tests, else_
|
If: tests!, else_&
|
||||||
Exec: expr, locals, globals
|
Exec: expr, locals&, globals&
|
||||||
From: modname, names
|
From: modname*, names*
|
||||||
Import: names
|
Import: names*
|
||||||
Raise: expr1, expr2, expr3
|
Raise: expr1&, expr2&, expr3&
|
||||||
TryFinally: body, final
|
TryFinally: body, final
|
||||||
TryExcept: body, handlers, else_
|
TryExcept: body, handlers!, else_&
|
||||||
Return: value
|
Return: value
|
||||||
Yield: value
|
Yield: value
|
||||||
Const: value
|
Const: value*
|
||||||
Print: nodes, dest
|
Print: nodes!, dest&
|
||||||
Printnl: nodes, dest
|
Printnl: nodes!, dest&
|
||||||
Discard: expr
|
Discard: expr
|
||||||
AugAssign: node, op, expr
|
AugAssign: node, op*, expr
|
||||||
Assign: nodes, expr
|
Assign: nodes!, expr
|
||||||
AssTuple: nodes
|
AssTuple: nodes!
|
||||||
AssList: nodes
|
AssList: nodes!
|
||||||
AssName: name, flags
|
AssName: name*, flags*
|
||||||
AssAttr: expr, attrname, flags
|
AssAttr: expr, attrname*, flags*
|
||||||
ListComp: expr, quals
|
ListComp: expr, quals!
|
||||||
ListCompFor: assign, list, ifs
|
ListCompFor: assign, list, ifs!
|
||||||
ListCompIf: test
|
ListCompIf: test
|
||||||
List: nodes
|
List: nodes!
|
||||||
Dict: items
|
Dict: items!
|
||||||
Not: expr
|
Not: expr
|
||||||
Compare: expr, ops
|
Compare: expr, ops!
|
||||||
Name: name
|
Name: name*
|
||||||
Global: names
|
Global: names
|
||||||
Backquote: expr
|
Backquote: expr
|
||||||
Getattr: expr, attrname
|
Getattr: expr, attrname*
|
||||||
CallFunc: node, args, star_args = None, dstar_args = None
|
CallFunc: node, args!, star_args& = None, dstar_args& = None
|
||||||
Keyword: name, expr
|
Keyword: name*, expr
|
||||||
Subscript: expr, flags, subs
|
Subscript: expr, flags*, subs!
|
||||||
Ellipsis:
|
Ellipsis:
|
||||||
Sliceobj: nodes
|
Sliceobj: nodes!
|
||||||
Slice: expr, flags, lower, upper
|
Slice: expr, flags*, lower&, upper&
|
||||||
Assert: test, fail
|
Assert: test, fail&
|
||||||
Tuple: nodes
|
Tuple: nodes!
|
||||||
Or: nodes
|
Or: nodes!
|
||||||
And: nodes
|
And: nodes!
|
||||||
Bitor: nodes
|
Bitor: nodes!
|
||||||
Bitxor: nodes
|
Bitxor: nodes!
|
||||||
Bitand: nodes
|
Bitand: nodes!
|
||||||
LeftShift: (left, right)
|
LeftShift: (left, right)
|
||||||
RightShift: (left, right)
|
RightShift: (left, right)
|
||||||
Add: (left, right)
|
Add: (left, right)
|
||||||
|
@ -59,6 +67,7 @@ Mul: (left, right)
|
||||||
Div: (left, right)
|
Div: (left, right)
|
||||||
Mod: (left, right)
|
Mod: (left, right)
|
||||||
Power: (left, right)
|
Power: (left, right)
|
||||||
|
FloorDiv: (left, right)
|
||||||
UnaryAdd: expr
|
UnaryAdd: expr
|
||||||
UnarySub: expr
|
UnarySub: expr
|
||||||
Invert: expr
|
Invert: expr
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
"""Generate ast module from specification"""
|
"""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
|
import fileinput
|
||||||
import getopt
|
import getopt
|
||||||
|
@ -24,7 +31,13 @@ def strip_default(arg):
|
||||||
i = arg.find('=')
|
i = arg.find('=')
|
||||||
if i == -1:
|
if i == -1:
|
||||||
return arg
|
return arg
|
||||||
return arg[:i].strip()
|
t = arg[:i].strip()
|
||||||
|
return t
|
||||||
|
|
||||||
|
P_NODE = 1
|
||||||
|
P_OTHER = 2
|
||||||
|
P_NESTED = 3
|
||||||
|
P_NONE = 4
|
||||||
|
|
||||||
class NodeInfo:
|
class NodeInfo:
|
||||||
"""Each instance describes a specific AST node"""
|
"""Each instance describes a specific AST node"""
|
||||||
|
@ -32,9 +45,8 @@ class NodeInfo:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.args = args.strip()
|
self.args = args.strip()
|
||||||
self.argnames = self.get_argnames()
|
self.argnames = self.get_argnames()
|
||||||
|
self.argprops = self.get_argprops()
|
||||||
self.nargs = len(self.argnames)
|
self.nargs = len(self.argnames)
|
||||||
self.children = COMMA.join(["self.%s" % c
|
|
||||||
for c in self.argnames])
|
|
||||||
self.init = []
|
self.init = []
|
||||||
|
|
||||||
def get_argnames(self):
|
def get_argnames(self):
|
||||||
|
@ -47,12 +59,48 @@ class NodeInfo:
|
||||||
return [strip_default(arg.strip())
|
return [strip_default(arg.strip())
|
||||||
for arg in args.split(',') if arg]
|
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):
|
def gen_source(self):
|
||||||
buf = StringIO()
|
buf = StringIO()
|
||||||
print >> buf, "class %s(Node):" % self.name
|
print >> buf, "class %s(Node):" % self.name
|
||||||
print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
|
print >> buf, ' nodes["%s"] = "%s"' % (self.name.lower(), self.name)
|
||||||
self._gen_init(buf)
|
self._gen_init(buf)
|
||||||
|
print >> buf
|
||||||
self._gen_getChildren(buf)
|
self._gen_getChildren(buf)
|
||||||
|
print >> buf
|
||||||
|
self._gen_getChildNodes(buf)
|
||||||
|
print >> buf
|
||||||
self._gen_repr(buf)
|
self._gen_repr(buf)
|
||||||
buf.seek(0, 0)
|
buf.seek(0, 0)
|
||||||
return buf.read()
|
return buf.read()
|
||||||
|
@ -68,14 +116,57 @@ class NodeInfo:
|
||||||
print >> buf, "".join([" " + line for line in self.init])
|
print >> buf, "".join([" " + line for line in self.init])
|
||||||
|
|
||||||
def _gen_getChildren(self, buf):
|
def _gen_getChildren(self, buf):
|
||||||
print >> buf, " def _getChildren(self):"
|
print >> buf, " def getChildren(self):"
|
||||||
if self.argnames:
|
if len(self.argnames) == 0:
|
||||||
if self.nargs == 1:
|
|
||||||
print >> buf, " return %s," % self.children
|
|
||||||
else:
|
|
||||||
print >> buf, " return %s" % self.children
|
|
||||||
else:
|
|
||||||
print >> buf, " return ()"
|
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):
|
def _gen_repr(self, buf):
|
||||||
print >> buf, " def __repr__(self):"
|
print >> buf, " def __repr__(self):"
|
||||||
|
@ -98,6 +189,8 @@ def parse_spec(file):
|
||||||
classes = {}
|
classes = {}
|
||||||
cur = None
|
cur = None
|
||||||
for line in fileinput.input(file):
|
for line in fileinput.input(file):
|
||||||
|
if line.strip().startswith('#'):
|
||||||
|
continue
|
||||||
mo = rx_init.search(line)
|
mo = rx_init.search(line)
|
||||||
if mo is None:
|
if mo is None:
|
||||||
if cur is None:
|
if cur is None:
|
||||||
|
@ -149,6 +242,9 @@ def flatten(list):
|
||||||
l.append(elt)
|
l.append(elt)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
|
def flatten_nodes(list):
|
||||||
|
return [n for n in flatten(list) if isinstance(n, Node)]
|
||||||
|
|
||||||
def asList(nodes):
|
def asList(nodes):
|
||||||
l = []
|
l = []
|
||||||
for item in nodes:
|
for item in nodes:
|
||||||
|
@ -164,21 +260,19 @@ def asList(nodes):
|
||||||
|
|
||||||
nodes = {}
|
nodes = {}
|
||||||
|
|
||||||
class Node:
|
class Node: # an abstract base class
|
||||||
lineno = None
|
lineno = None # provide a lineno for nodes that don't have one
|
||||||
def getType(self):
|
def getType(self):
|
||||||
pass
|
pass # implemented by subclass
|
||||||
def getChildren(self):
|
def getChildren(self):
|
||||||
# XXX It would be better to generate flat values to begin with
|
pass # implemented by subclasses
|
||||||
return flatten(self._getChildren())
|
|
||||||
def asList(self):
|
def asList(self):
|
||||||
return tuple(asList(self.getChildren()))
|
return tuple(asList(self.getChildren()))
|
||||||
def getChildNodes(self):
|
def getChildNodes(self):
|
||||||
return [n for n in self.getChildren() if isinstance(n, Node)]
|
pass # implemented by subclasses
|
||||||
|
|
||||||
class EmptyNode(Node):
|
class EmptyNode(Node):
|
||||||
def __init__(self):
|
pass
|
||||||
self.lineno = None
|
|
||||||
|
|
||||||
### EPILOGUE
|
### EPILOGUE
|
||||||
klasses = globals()
|
klasses = globals()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue