# Copyright 2006 Google, Inc. All Rights Reserved.# Licensed to PSF under a Contributor Agreement."""Pattern compiler.The grammar is taken from PatternGrammar.txt.The compiler compiles a pattern to a pytree.*Pattern instance."""__author__ = "Guido van Rossum <guido@python.org>"# Python importsimport io# Fairly local importsfrom .pgen2 import driver, literals, token, tokenize, parse, grammar# Really local importsfrom . import pytreefrom . import pygramclass PatternSyntaxError(Exception):passdef tokenize_wrapper(input):"""Tokenizes a string suppressing significant whitespace."""skip = {token.NEWLINE, token.INDENT, token.DEDENT}tokens = tokenize.generate_tokens(io.StringIO(input).readline)for quintuple in tokens:type, value, start, end, line_text = quintupleif type not in skip:yield quintupleclass PatternCompiler(object):def __init__(self, grammar_file=None):"""Initializer.Takes an optional alternative filename for the pattern grammar."""if grammar_file is None:self.grammar = pygram.pattern_grammarself.syms = pygram.pattern_symbolselse:self.grammar = driver.load_grammar(grammar_file)self.syms = pygram.Symbols(self.grammar)self.pygrammar = pygram.python_grammarself.pysyms = pygram.python_symbolsself.driver = driver.Driver(self.grammar, convert=pattern_convert)def compile_pattern(self, input, debug=False, with_tree=False):"""Compiles a pattern string to a nested pytree.*Pattern object."""tokens = tokenize_wrapper(input)try:root = self.driver.parse_tokens(tokens, debug=debug)except parse.ParseError as e:raise PatternSyntaxError(str(e)) from Noneif with_tree:return self.compile_node(root), rootelse:return self.compile_node(root)def compile_node(self, node):"""Compiles a node, recursively.This is one big switch on the node type."""# XXX Optimize certain Wildcard-containing-Wildcard patterns# that can be mergedif node.type == self.syms.Matcher:node = node.children[0] # Avoid unneeded recursionif node.type == self.syms.Alternatives:# Skip the odd children since they are just '|' tokensalts = [self.compile_node(ch) for ch in node.children[::2]]if len(alts) == 1:return alts[0]p = pytree.WildcardPattern([[a] for a in alts], min=1, max=1)return p.optimize()if node.type == self.syms.Alternative:units = [self.compile_node(ch) for ch in node.children]if len(units) == 1:return units[0]p = pytree.WildcardPattern([units], min=1, max=1)return p.optimize()if node.type == self.syms.NegatedUnit:pattern = self.compile_basic(node.children[1:])p = pytree.NegatedPattern(pattern)return p.optimize()assert node.type == self.syms.Unitname = Nonenodes = node.childrenif len(nodes) >= 3 and nodes[1].type == token.EQUAL:name = nodes[0].valuenodes = nodes[2:]repeat = Noneif len(nodes) >= 2 and nodes[-1].type == self.syms.Repeater:repeat = nodes[-1]nodes = nodes[:-1]# Now we've reduced it to: STRING | NAME [Details] | (...) | [...]pattern = self.compile_basic(nodes, repeat)if repeat is not None:assert repeat.type == self.syms.Repeaterchildren = repeat.childrenchild = children[0]if child.type == token.STAR:min = 0max = pytree.HUGEelif child.type == token.PLUS:min = 1max = pytree.HUGEelif child.type == token.LBRACE:assert children[-1].type == token.RBRACEassert len(children) in (3, 5)min = max = self.get_int(children[1])if len(children) == 5:max = self.get_int(children[3])else:assert Falseif min != 1 or max != 1:pattern = pattern.optimize()pattern = pytree.WildcardPattern([[pattern]], min=min, max=max)if name is not None:pattern.name = namereturn pattern.optimize()def compile_basic(self, nodes, repeat=None):# Compile STRING | NAME [Details] | (...) | [...]assert len(nodes) >= 1node = nodes[0]if node.type == token.STRING:value = str(literals.evalString(node.value))return pytree.LeafPattern(_type_of_literal(value), value)elif node.type == token.NAME:value = node.valueif value.isupper():if value not in TOKEN_MAP:raise PatternSyntaxError("Invalid token: %r" % value)if nodes[1:]:raise PatternSyntaxError("Can't have details for token")return pytree.LeafPattern(TOKEN_MAP[value])else:if value == "any":type = Noneelif not value.startswith("_"):type = getattr(self.pysyms, value, None)if type is None:raise PatternSyntaxError("Invalid symbol: %r" % value)if nodes[1:]: # Details presentcontent = [self.compile_node(nodes[1].children[1])]else:content = Nonereturn pytree.NodePattern(type, content)elif node.value == "(":return self.compile_node(nodes[1])elif node.value == "[":assert repeat is Nonesubpattern = self.compile_node(nodes[1])return pytree.WildcardPattern([[subpattern]], min=0, max=1)assert False, nodedef get_int(self, node):assert node.type == token.NUMBERreturn int(node.value)# Map named tokens to the type value for a LeafPatternTOKEN_MAP = {"NAME": token.NAME,"STRING": token.STRING,"NUMBER": token.NUMBER,"TOKEN": None}def _type_of_literal(value):if value[0].isalpha():return token.NAMEelif value in grammar.opmap:return grammar.opmap[value]else:return Nonedef pattern_convert(grammar, raw_node_info):"""Converts raw node information to a Node or Leaf instance."""type, value, context, children = raw_node_infoif children or type in grammar.number2symbol:return pytree.Node(type, children, context=context)else:return pytree.Leaf(type, value, context=context)def compile_pattern(pattern):return PatternCompiler().compile_pattern(pattern)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。