"""Generate ast module from specificationThis script generates the ast module from a simple specification,which makes it easy to accomodate changes in the grammar. Thisapproach would be quite reasonable if the grammar changed often.Instead, it is rather complex to generate the appropriate code. Andthe Node interface has changed more often than the grammar."""import fileinputimport reimport sysfrom StringIO import StringIOSPEC = "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, epidef strip_default(arg):"""Return the argname from an 'arg = default' string"""i = arg.find('=')if i == -1:return argt = arg[:i].strip()return tP_NODE = 1P_OTHER = 2P_NESTED = 3P_NONE = 4class NodeInfo:"""Each instance describes a specific AST node"""def __init__(self, name, args):self.name = nameself.args = args.strip()self.argnames = self.get_argnames()self.argprops = self.get_argprops()self.nargs = len(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.argsreturn [strip_default(arg.strip())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_NODEfor i in range(len(self.argnames)):arg = self.argnames[i]if arg.endswith('*'):arg = self.argnames[i] = arg[:-1]d[arg] = P_OTHERhardest_arg = max(hardest_arg, P_OTHER)elif arg.endswith('!'):arg = self.argnames[i] = arg[:-1]d[arg] = P_NESTEDhardest_arg = max(hardest_arg, P_NESTED)elif arg.endswith('&'):arg = self.argnames[i] = arg[:-1]d[arg] = P_NONEhardest_arg = max(hardest_arg, P_NONE)else:d[arg] = P_NODEself.hardest_arg = hardest_argif hardest_arg > P_NODE:self.args = self.args.replace('*', '')self.args = self.args.replace('!', '')self.args = self.args.replace('&', '')return ddef gen_source(self):buf = StringIO()print >> buf, "class %s(Node):" % self.nameself._gen_init(buf)print >> bufself._gen_getChildren(buf)print >> bufself._gen_getChildNodes(buf)print >> bufself._gen_repr(buf)buf.seek(0, 0)return buf.read()def _gen_init(self, buf):if self.args:print >> buf, " def __init__(self, %s, lineno=None):" % self.argselse:print >> buf, " def __init__(self, lineno=None):"if self.argnames:for name in self.argnames:print >> buf, " self.%s = %s" % (name, name)print >> buf, " self.lineno = lineno"# Copy the lines in self.init, indented four spaces. The rstrip()# business is to get rid of the four spaces if line happens to be# empty, so that reindent.py is happy with the output.for line in self.init:print >> buf, (" " + line).rstrip()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" % cfor c in self.argnames])if self.nargs == 1:print >> buf, " return %s," % clistelse:print >> buf, " return %s" % clistelse:if len(self.argnames) == 1:print >> buf, " return tuple(flatten(self.%s))" % self.argnames[0]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" % cfor c in self.argnamesif 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, " nodelist = []"template = " nodelist.%s(%sself.%s%s)"for name in self.argnames:if self.argprops[name] == P_NONE:tmp = (" if self.%s is not None:\n"" nodelist.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(nodelist)"def _gen_repr(self, buf):print >> buf, " def __repr__(self):"if self.argnames:fmt = COMMA.join(["%s"] * self.nargs)if '(' in self.args:fmt = '(%s)' % fmtvals = ["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.namerx_init = re.compile('init\((.*)\):')def parse_spec(file):classes = {}cur = Nonefor line in fileinput.input(file):if line.strip().startswith('#'):continuemo = rx_init.search(line)if mo is None:if cur is None:# a normal entrytry:name, args = line.split(':')except ValueError:continueclasses[name] = NodeInfo(name, args)cur = Noneelse:# some code for the __init__ methodcur.init.append(line)else:# some extra code for a Node's __init__ methodname = mo.group(1)cur = classes[name]return sorted(classes.values(), key=lambda n: n.name)def main():prologue, epilogue = load_boilerplate(sys.argv[-1])print prologueclasses = parse_spec(SPEC)for info in classes:print info.gen_source()print epilogueif __name__ == "__main__":main()sys.exit(0)### PROLOGUE"""Python abstract syntax node definitionsThis file is automatically generated by Tools/compiler/astgen.py"""from consts import CO_VARARGS, CO_VARKEYWORDSdef flatten(seq):l = []for elt in seq:t = type(elt)if t is tuple or t is list:for elt2 in flatten(elt):l.append(elt2)else:l.append(elt)return ldef flatten_nodes(seq):return [n for n in flatten(seq) if isinstance(n, Node)]nodes = {}class Node:"""Abstract base class for ast nodes."""def getChildren(self):pass # implemented by subclassesdef __iter__(self):for n in self.getChildren():yield ndef asList(self): # for backwards compatibilityreturn self.getChildren()def getChildNodes(self):pass # implemented by subclassesclass EmptyNode(Node):passclass Expression(Node):# Expression is an artificial node class to support "eval"nodes["expression"] = "Expression"def __init__(self, node):self.node = nodedef getChildren(self):return self.node,def getChildNodes(self):return self.node,def __repr__(self):return "Expression(%s)" % (repr(self.node))### EPILOGUEfor name, obj in globals().items():if isinstance(obj, type) and issubclass(obj, Node):nodes[name.lower()] = obj
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。