towards 1.6b1

This commit is contained in:
Fredrik Lundh 2000-06-29 08:58:44 +00:00
parent 102f3ad676
commit 436c3d58a2
5 changed files with 573 additions and 341 deletions

View File

@ -12,6 +12,7 @@
# #
import sre_compile import sre_compile
import sre_parse
# flags # flags
I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE
@ -20,6 +21,13 @@ M = MULTILINE = sre_compile.SRE_FLAG_MULTILINE
S = DOTALL = sre_compile.SRE_FLAG_DOTALL S = DOTALL = sre_compile.SRE_FLAG_DOTALL
X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE X = VERBOSE = sre_compile.SRE_FLAG_VERBOSE
# sre extensions (may or may not be in 1.6 final)
T = TEMPLATE = sre_compile.SRE_FLAG_TEMPLATE
U = UNICODE = sre_compile.SRE_FLAG_UNICODE
# sre exception
error = sre_parse.error
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# public interface # public interface
@ -46,6 +54,9 @@ def findall(pattern, string, maxsplit=0):
def compile(pattern, flags=0): def compile(pattern, flags=0):
return _compile(pattern, flags) return _compile(pattern, flags)
def template(pattern, flags=0):
return _compile(pattern, flags|T)
def escape(pattern): def escape(pattern):
s = list(pattern) s = list(pattern)
for i in range(len(pattern)): for i in range(len(pattern)):
@ -83,18 +94,14 @@ def _sub(pattern, template, string, count=0):
# internal: pattern.sub implementation hook # internal: pattern.sub implementation hook
return _subn(pattern, template, string, count)[0] return _subn(pattern, template, string, count)[0]
def _expand(match, template):
# internal: expand template
return template # FIXME
def _subn(pattern, template, string, count=0): def _subn(pattern, template, string, count=0):
# internal: pattern.subn implementation hook # internal: pattern.subn implementation hook
if callable(template): if callable(template):
filter = template filter = template
else: else:
# FIXME: prepare template template = sre_parse.parse_template(template, pattern)
def filter(match, template=template): def filter(match, template=template):
return _expand(match, template) return sre_parse.expand_template(template, match)
n = i = 0 n = i = 0
s = [] s = []
append = s.append append = s.append
@ -108,6 +115,8 @@ def _subn(pattern, template, string, count=0):
append(string[i:j]) append(string[i:j])
append(filter(m)) append(filter(m))
i = m.end() i = m.end()
if i <= j:
break
n = n + 1 n = n + 1
if i < len(string): if i < len(string):
append(string[i:]) append(string[i:])
@ -126,6 +135,8 @@ def _split(pattern, string, maxsplit=0):
j = m.start() j = m.start()
append(string[i:j]) append(string[i:j])
i = m.end() i = m.end()
if i <= j:
break
n = n + 1 n = n + 1
if i < len(string): if i < len(string):
append(string[i:]) append(string[i:])

View File

@ -48,7 +48,7 @@ class Code:
print self.data print self.data
raise raise
def _compile(code, pattern, flags, level=0): def _compile(code, pattern, flags):
append = code.append append = code.append
for op, av in pattern: for op, av in pattern:
if op is ANY: if op is ANY:
@ -70,23 +70,26 @@ def _compile(code, pattern, flags, level=0):
tail = [] tail = []
for av in av[1]: for av in av[1]:
skip = len(code); append(0) skip = len(code); append(0)
_compile(code, av, flags, level) _compile(code, av, flags)
append(OPCODES[JUMP]) ## append(OPCODES[SUCCESS])
tail.append(len(code)); append(0) append(OPCODES[JUMP])
tail.append(len(code)); append(0)
code[skip] = len(code) - skip code[skip] = len(code) - skip
append(0) # end of branch append(0) # end of branch
for tail in tail: for tail in tail:
code[tail] = len(code) - tail code[tail] = len(code) - tail
elif op is CALL: elif op is CALL:
append(OPCODES[op]) append(OPCODES[op])
skip = len(code); append(0) skip = len(code); append(0)
_compile(code, av, flags, level+1) _compile(code, av, flags)
append(OPCODES[SUCCESS]) append(OPCODES[SUCCESS])
code[skip] = len(code) - skip code[skip] = len(code) - skip
elif op is CATEGORY: # not used by current parser elif op is CATEGORY:
append(OPCODES[op]) append(OPCODES[op])
if flags & SRE_FLAG_LOCALE: if flags & SRE_FLAG_LOCALE:
append(CH_LOCALE[CHCODES[av]]) append(CH_LOCALE[CHCODES[av]])
elif flags & SRE_FLAG_UNICODE:
append(CH_UNICODE[CHCODES[av]])
else: else:
append(CHCODES[av]) append(CHCODES[av])
elif op is GROUP: elif op is GROUP:
@ -98,8 +101,8 @@ def _compile(code, pattern, flags, level=0):
elif op is IN: elif op is IN:
if flags & SRE_FLAG_IGNORECASE: if flags & SRE_FLAG_IGNORECASE:
append(OPCODES[OP_IGNORE[op]]) append(OPCODES[OP_IGNORE[op]])
def fixup(literal): def fixup(literal, flags=flags):
return ord(literal.lower()) return _sre.getlower(ord(literal), flags)
else: else:
append(OPCODES[op]) append(OPCODES[op])
fixup = ord fixup = ord
@ -116,6 +119,8 @@ def _compile(code, pattern, flags, level=0):
elif op is CATEGORY: elif op is CATEGORY:
if flags & SRE_FLAG_LOCALE: if flags & SRE_FLAG_LOCALE:
append(CH_LOCALE[CHCODES[av]]) append(CH_LOCALE[CHCODES[av]])
elif flags & SRE_FLAG_UNICODE:
append(CH_UNICODE[CHCODES[av]])
else: else:
append(CHCODES[av]) append(CHCODES[av])
else: else:
@ -125,42 +130,49 @@ def _compile(code, pattern, flags, level=0):
elif op in (LITERAL, NOT_LITERAL): elif op in (LITERAL, NOT_LITERAL):
if flags & SRE_FLAG_IGNORECASE: if flags & SRE_FLAG_IGNORECASE:
append(OPCODES[OP_IGNORE[op]]) append(OPCODES[OP_IGNORE[op]])
append(ord(av.lower()))
else: else:
append(OPCODES[op]) append(OPCODES[op])
append(ord(av)) append(ord(av))
elif op is MARK: elif op is MARK:
append(OPCODES[op]) append(OPCODES[op])
append(av) append(av)
elif op in (REPEAT, MIN_REPEAT, MAX_REPEAT): elif op in (REPEAT, MIN_REPEAT, MAX_REPEAT):
lo, hi = av[2].getwidth() if flags & SRE_FLAG_TEMPLATE:
if lo == 0: append(OPCODES[REPEAT])
raise SyntaxError, "cannot repeat zero-width items"
if lo == hi == 1 and op is MAX_REPEAT:
append(OPCODES[MAX_REPEAT_ONE])
skip = len(code); append(0) skip = len(code); append(0)
append(av[0]) append(av[0])
append(av[1]) append(av[1])
_compile(code, av[2], flags, level+1) _compile(code, av[2], flags)
append(OPCODES[SUCCESS]) append(OPCODES[SUCCESS])
code[skip] = len(code) - skip code[skip] = len(code) - skip
else: else:
append(OPCODES[op]) lo, hi = av[2].getwidth()
skip = len(code); append(0) if lo == 0:
append(av[0]) raise error, "nothing to repeat"
append(av[1]) if 0 and lo == hi == 1 and op is MAX_REPEAT:
_compile(code, av[2], flags, level+1) # FIXME: <fl> need a better way to figure out when
if op is MIN_REPEAT: # it's safe to use this one (in the parser, probably)
append(OPCODES[MIN_UNTIL]) append(OPCODES[MAX_REPEAT_ONE])
skip = len(code); append(0)
append(av[0])
append(av[1])
_compile(code, av[2], flags)
append(OPCODES[SUCCESS])
code[skip] = len(code) - skip
else: else:
append(OPCODES[MAX_UNTIL]) append(OPCODES[op])
code[skip] = len(code) - skip skip = len(code); append(0)
append(av[0])
append(av[1])
_compile(code, av[2], flags)
append(OPCODES[SUCCESS])
code[skip] = len(code) - skip
elif op is SUBPATTERN: elif op is SUBPATTERN:
group = av[0] group = av[0]
if group: if group:
append(OPCODES[MARK]) append(OPCODES[MARK])
append((group-1)*2) append((group-1)*2)
_compile(code, av[1], flags, level+1) _compile(code, av[1], flags)
if group: if group:
append(OPCODES[MARK]) append(OPCODES[MARK])
append((group-1)*2+1) append((group-1)*2+1)

View File

@ -15,6 +15,11 @@
# other compatibility work. # other compatibility work.
# #
# should this really be here?
class error(Exception):
pass
# operators # operators
FAILURE = "failure" FAILURE = "failure"
@ -30,20 +35,20 @@ GROUP = "group"
GROUP_IGNORE = "group_ignore" GROUP_IGNORE = "group_ignore"
IN = "in" IN = "in"
IN_IGNORE = "in_ignore" IN_IGNORE = "in_ignore"
INFO = "info"
JUMP = "jump" JUMP = "jump"
LITERAL = "literal" LITERAL = "literal"
LITERAL_IGNORE = "literal_ignore" LITERAL_IGNORE = "literal_ignore"
MARK = "mark" MARK = "mark"
MAX_REPEAT = "max_repeat" MAX_REPEAT = "max_repeat"
MAX_REPEAT_ONE = "max_repeat_one" MAX_REPEAT_ONE = "max_repeat_one"
MAX_UNTIL = "max_until"
MIN_REPEAT = "min_repeat" MIN_REPEAT = "min_repeat"
MIN_UNTIL = "min_until"
NEGATE = "negate" NEGATE = "negate"
NOT_LITERAL = "not_literal" NOT_LITERAL = "not_literal"
NOT_LITERAL_IGNORE = "not_literal_ignore" NOT_LITERAL_IGNORE = "not_literal_ignore"
RANGE = "range" RANGE = "range"
REPEAT = "repeat" REPEAT = "repeat"
REPEAT_ONE = "repeat_one"
SUBPATTERN = "subpattern" SUBPATTERN = "subpattern"
# positions # positions
@ -63,14 +68,16 @@ CATEGORY_WORD = "category_word"
CATEGORY_NOT_WORD = "category_not_word" CATEGORY_NOT_WORD = "category_not_word"
CATEGORY_LINEBREAK = "category_linebreak" CATEGORY_LINEBREAK = "category_linebreak"
CATEGORY_NOT_LINEBREAK = "category_not_linebreak" CATEGORY_NOT_LINEBREAK = "category_not_linebreak"
CATEGORY_LOC_DIGIT = "category_loc_digit"
CATEGORY_LOC_NOT_DIGIT = "category_loc_not_digit"
CATEGORY_LOC_SPACE = "category_loc_space"
CATEGORY_LOC_NOT_SPACE = "category_loc_not_space"
CATEGORY_LOC_WORD = "category_loc_word" CATEGORY_LOC_WORD = "category_loc_word"
CATEGORY_LOC_NOT_WORD = "category_loc_not_word" CATEGORY_LOC_NOT_WORD = "category_loc_not_word"
CATEGORY_LOC_LINEBREAK = "category_loc_linebreak" CATEGORY_UNI_DIGIT = "category_uni_digit"
CATEGORY_LOC_NOT_LINEBREAK = "category_loc_not_linebreak" CATEGORY_UNI_NOT_DIGIT = "category_uni_not_digit"
CATEGORY_UNI_SPACE = "category_uni_space"
CATEGORY_UNI_NOT_SPACE = "category_uni_not_space"
CATEGORY_UNI_WORD = "category_uni_word"
CATEGORY_UNI_NOT_WORD = "category_uni_not_word"
CATEGORY_UNI_LINEBREAK = "category_uni_linebreak"
CATEGORY_UNI_NOT_LINEBREAK = "category_uni_not_linebreak"
OPCODES = [ OPCODES = [
@ -85,12 +92,13 @@ OPCODES = [
CATEGORY, CATEGORY,
GROUP, GROUP_IGNORE, GROUP, GROUP_IGNORE,
IN, IN_IGNORE, IN, IN_IGNORE,
INFO,
JUMP, JUMP,
LITERAL, LITERAL_IGNORE, LITERAL, LITERAL_IGNORE,
MARK, MARK,
MAX_REPEAT, MAX_UNTIL, MAX_REPEAT,
MAX_REPEAT_ONE, MAX_REPEAT_ONE,
MIN_REPEAT, MIN_UNTIL, MIN_REPEAT,
NOT_LITERAL, NOT_LITERAL_IGNORE, NOT_LITERAL, NOT_LITERAL_IGNORE,
NEGATE, NEGATE,
RANGE, RANGE,
@ -106,10 +114,11 @@ ATCODES = [
CHCODES = [ CHCODES = [
CATEGORY_DIGIT, CATEGORY_NOT_DIGIT, CATEGORY_SPACE, CATEGORY_DIGIT, CATEGORY_NOT_DIGIT, CATEGORY_SPACE,
CATEGORY_NOT_SPACE, CATEGORY_WORD, CATEGORY_NOT_WORD, CATEGORY_NOT_SPACE, CATEGORY_WORD, CATEGORY_NOT_WORD,
CATEGORY_LINEBREAK, CATEGORY_NOT_LINEBREAK, CATEGORY_LOC_DIGIT, CATEGORY_LINEBREAK, CATEGORY_NOT_LINEBREAK, CATEGORY_LOC_WORD,
CATEGORY_LOC_NOT_DIGIT, CATEGORY_LOC_SPACE, CATEGORY_LOC_NOT_WORD, CATEGORY_UNI_DIGIT, CATEGORY_UNI_NOT_DIGIT,
CATEGORY_LOC_NOT_SPACE, CATEGORY_LOC_WORD, CATEGORY_LOC_NOT_WORD, CATEGORY_UNI_SPACE, CATEGORY_UNI_NOT_SPACE, CATEGORY_UNI_WORD,
CATEGORY_LOC_LINEBREAK, CATEGORY_LOC_NOT_LINEBREAK CATEGORY_UNI_NOT_WORD, CATEGORY_UNI_LINEBREAK,
CATEGORY_UNI_NOT_LINEBREAK
] ]
def makedict(list): def makedict(list):
@ -138,23 +147,35 @@ AT_MULTILINE = {
} }
CH_LOCALE = { CH_LOCALE = {
CATEGORY_DIGIT: CATEGORY_LOC_DIGIT, CATEGORY_DIGIT: CATEGORY_DIGIT,
CATEGORY_NOT_DIGIT: CATEGORY_LOC_NOT_DIGIT, CATEGORY_NOT_DIGIT: CATEGORY_NOT_DIGIT,
CATEGORY_SPACE: CATEGORY_LOC_SPACE, CATEGORY_SPACE: CATEGORY_SPACE,
CATEGORY_NOT_SPACE: CATEGORY_LOC_NOT_SPACE, CATEGORY_NOT_SPACE: CATEGORY_NOT_SPACE,
CATEGORY_WORD: CATEGORY_LOC_WORD, CATEGORY_WORD: CATEGORY_LOC_WORD,
CATEGORY_NOT_WORD: CATEGORY_LOC_NOT_WORD, CATEGORY_NOT_WORD: CATEGORY_LOC_NOT_WORD,
CATEGORY_LINEBREAK: CATEGORY_LOC_LINEBREAK, CATEGORY_LINEBREAK: CATEGORY_LINEBREAK,
CATEGORY_NOT_LINEBREAK: CATEGORY_LOC_NOT_LINEBREAK CATEGORY_NOT_LINEBREAK: CATEGORY_NOT_LINEBREAK
}
CH_UNICODE = {
CATEGORY_DIGIT: CATEGORY_UNI_DIGIT,
CATEGORY_NOT_DIGIT: CATEGORY_UNI_NOT_DIGIT,
CATEGORY_SPACE: CATEGORY_UNI_SPACE,
CATEGORY_NOT_SPACE: CATEGORY_UNI_NOT_SPACE,
CATEGORY_WORD: CATEGORY_UNI_WORD,
CATEGORY_NOT_WORD: CATEGORY_UNI_NOT_WORD,
CATEGORY_LINEBREAK: CATEGORY_UNI_LINEBREAK,
CATEGORY_NOT_LINEBREAK: CATEGORY_UNI_NOT_LINEBREAK
} }
# flags # flags
SRE_FLAG_TEMPLATE = 1 # NYI SRE_FLAG_TEMPLATE = 1
SRE_FLAG_IGNORECASE = 2 SRE_FLAG_IGNORECASE = 2
SRE_FLAG_LOCALE = 4 SRE_FLAG_LOCALE = 4
SRE_FLAG_MULTILINE = 8 SRE_FLAG_MULTILINE = 8
SRE_FLAG_DOTALL = 16 SRE_FLAG_DOTALL = 16
SRE_FLAG_VERBOSE = 32 SRE_FLAG_UNICODE = 32
SRE_FLAG_VERBOSE = 64
if __name__ == "__main__": if __name__ == "__main__":
import string import string
@ -168,5 +189,12 @@ if __name__ == "__main__":
dump(f, OPCODES, "SRE_OP") dump(f, OPCODES, "SRE_OP")
dump(f, ATCODES, "SRE") dump(f, ATCODES, "SRE")
dump(f, CHCODES, "SRE") dump(f, CHCODES, "SRE")
f.write("#define SRE_FLAG_TEMPLATE %d\n" % SRE_FLAG_TEMPLATE)
f.write("#define SRE_FLAG_IGNORECASE %d\n" % SRE_FLAG_IGNORECASE)
f.write("#define SRE_FLAG_LOCALE %d\n" % SRE_FLAG_LOCALE)
f.write("#define SRE_FLAG_MULTILINE %d\n" % SRE_FLAG_MULTILINE)
f.write("#define SRE_FLAG_DOTALL %d\n" % SRE_FLAG_DOTALL)
f.write("#define SRE_FLAG_UNICODE %d\n" % SRE_FLAG_UNICODE)
f.write("#define SRE_FLAG_VERBOSE %d\n" % SRE_FLAG_VERBOSE)
f.close() f.close()
print "done" print "done"

View File

@ -20,14 +20,15 @@ import _sre
from sre_constants import * from sre_constants import *
# FIXME: should be 65535, but the array module currently chokes on # FIXME: <fl> should be 65535, but the array module currently chokes
# unsigned integers larger than 32767... # on unsigned integers larger than 32767 [fixed in 1.6b1?]
MAXREPEAT = int(2L**(_sre.getcodesize()*8-1))-1 MAXREPEAT = int(2L**(_sre.getcodesize()*8-1))-1
SPECIAL_CHARS = ".\\[{()*+?^$|" SPECIAL_CHARS = ".\\[{()*+?^$|"
REPEAT_CHARS = "*+?{" REPEAT_CHARS = "*+?{"
# FIXME: string in tuple tests may explode with if char is unicode :-( # FIXME: <fl> string in tuple tests may explode with if char is
# unicode [fixed in 1.6b1?]
DIGITS = tuple(string.digits) DIGITS = tuple(string.digits)
OCTDIGITS = tuple("01234567") OCTDIGITS = tuple("01234567")
@ -59,12 +60,15 @@ CATEGORIES = {
} }
FLAGS = { FLAGS = {
# standard flags
"i": SRE_FLAG_IGNORECASE, "i": SRE_FLAG_IGNORECASE,
"L": SRE_FLAG_LOCALE, "L": SRE_FLAG_LOCALE,
"m": SRE_FLAG_MULTILINE, "m": SRE_FLAG_MULTILINE,
"s": SRE_FLAG_DOTALL, "s": SRE_FLAG_DOTALL,
"t": SRE_FLAG_TEMPLATE,
"x": SRE_FLAG_VERBOSE, "x": SRE_FLAG_VERBOSE,
# extensions
"t": SRE_FLAG_TEMPLATE,
"u": SRE_FLAG_UNICODE,
} }
class State: class State:
@ -151,7 +155,7 @@ class Tokenizer:
try: try:
c = self.string[self.index + 1] c = self.string[self.index + 1]
except IndexError: except IndexError:
raise SyntaxError, "bogus escape" raise error, "bogus escape"
char = char + c char = char + c
self.index = self.index + len(char) self.index = self.index + len(char)
return char return char
@ -205,7 +209,7 @@ def _class_escape(source, escape):
return LITERAL, escape[1] return LITERAL, escape[1]
except ValueError: except ValueError:
pass pass
raise SyntaxError, "bogus escape: %s" % repr(escape) raise error, "bogus escape: %s" % repr(escape)
def _escape(source, escape, state): def _escape(source, escape, state):
# handle escape code in expression # handle escape code in expression
@ -241,13 +245,12 @@ def _escape(source, escape, state):
return LITERAL, escape[1] return LITERAL, escape[1]
except ValueError: except ValueError:
pass pass
raise SyntaxError, "bogus escape: %s" % repr(escape) raise error, "bogus escape: %s" % repr(escape)
def _branch(pattern, items): def _branch(pattern, items):
# form a branch operator from a set of items (FIXME: move this # form a branch operator from a set of items
# optimization to the compiler module!)
subpattern = SubPattern(pattern) subpattern = SubPattern(pattern)
@ -332,7 +335,7 @@ def _parse(source, state, flags=0):
elif this: elif this:
code1 = LITERAL, this code1 = LITERAL, this
else: else:
raise SyntaxError, "unexpected end of regular expression" raise error, "unexpected end of regular expression"
if source.match("-"): if source.match("-"):
# potential range # potential range
this = source.get() this = source.get()
@ -346,9 +349,9 @@ def _parse(source, state, flags=0):
else: else:
code2 = LITERAL, this code2 = LITERAL, this
if code1[0] != LITERAL or code2[0] != LITERAL: if code1[0] != LITERAL or code2[0] != LITERAL:
raise SyntaxError, "illegal range" raise error, "illegal range"
if len(code1[1]) != 1 or len(code2[1]) != 1: if len(code1[1]) != 1 or len(code2[1]) != 1:
raise SyntaxError, "illegal range" raise error, "illegal range"
set.append((RANGE, (code1[1], code2[1]))) set.append((RANGE, (code1[1], code2[1])))
else: else:
if code1[0] is IN: if code1[0] is IN:
@ -383,19 +386,19 @@ def _parse(source, state, flags=0):
else: else:
hi = lo hi = lo
if not source.match("}"): if not source.match("}"):
raise SyntaxError, "bogus range" raise error, "bogus range"
if lo: if lo:
min = int(lo) min = int(lo)
if hi: if hi:
max = int(hi) max = int(hi)
# FIXME: <fl> check that hi >= lo! # FIXME: <fl> check that hi >= lo!
else: else:
raise SyntaxError, "not supported" raise error, "not supported"
# figure out which item to repeat # figure out which item to repeat
if subpattern: if subpattern:
item = subpattern[-1:] item = subpattern[-1:]
else: else:
raise SyntaxError, "nothing to repeat" raise error, "nothing to repeat"
if source.match("?"): if source.match("?"):
subpattern[-1] = (MIN_REPEAT, (min, max, item)) subpattern[-1] = (MIN_REPEAT, (min, max, item))
else: else:
@ -418,7 +421,7 @@ def _parse(source, state, flags=0):
while 1: while 1:
char = source.get() char = source.get()
if char is None: if char is None:
raise SyntaxError, "unterminated name" raise error, "unterminated name"
if char == ">": if char == ">":
break break
# FIXME: check for valid character # FIXME: check for valid character
@ -426,22 +429,21 @@ def _parse(source, state, flags=0):
group = 1 group = 1
elif source.match("="): elif source.match("="):
# named backreference # named backreference
raise SyntaxError, "not yet implemented" raise error, "not yet implemented"
else: else:
char = source.get() char = source.get()
if char is None: if char is None:
raise SyntaxError, "unexpected end of pattern" raise error, "unexpected end of pattern"
raise SyntaxError, "unknown specifier: ?P%s" % char raise error, "unknown specifier: ?P%s" % char
elif source.match(":"): elif source.match(":"):
# non-capturing group # non-capturing group
group = 2 group = 2
elif source.match("#"): elif source.match("#"):
# comment # comment
while 1: while 1:
char = source.get() if source.next is None or source.next == ")":
if char is None or char == ")":
break break
source.get()
else: else:
# flags # flags
while FLAGS.has_key(source.next): while FLAGS.has_key(source.next):
@ -465,13 +467,13 @@ def _parse(source, state, flags=0):
elif source.match("|"): elif source.match("|"):
b.append(p) b.append(p)
else: else:
raise SyntaxError, "group not properly closed" raise error, "group not properly closed"
else: else:
while 1: while 1:
char = source.get() char = source.get()
if char is None or char == ")": if char is None or char == ")":
break break
# FIXME: skip characters? raise error, "unknown extension"
elif this == "^": elif this == "^":
subpattern.append((AT, AT_BEGINNING)) subpattern.append((AT, AT_BEGINNING))
@ -484,7 +486,7 @@ def _parse(source, state, flags=0):
subpattern.append(code) subpattern.append(code)
else: else:
raise SyntaxError, "parser error" raise error, "parser error"
return subpattern return subpattern
@ -499,17 +501,17 @@ def parse(pattern, flags=0):
if tail == "|": if tail == "|":
b.append(p) b.append(p)
elif tail == ")": elif tail == ")":
raise SyntaxError, "unbalanced parenthesis" raise error, "unbalanced parenthesis"
elif tail is None: elif tail is None:
if b: if b:
b.append(p) b.append(p)
p = _branch(state, b) p = _branch(state, b)
break break
else: else:
raise SyntaxError, "bogus characters at end of regular expression" raise error, "bogus characters at end of regular expression"
return p return p
def parse_replacement(source, pattern): def parse_template(source, pattern):
# parse 're' replacement string into list of literals and # parse 're' replacement string into list of literals and
# group references # group references
s = Tokenizer(source) s = Tokenizer(source)
@ -520,15 +522,56 @@ def parse_replacement(source, pattern):
if this is None: if this is None:
break # end of replacement string break # end of replacement string
if this and this[0] == "\\": if this and this[0] == "\\":
try: if this == "\\g":
a(LITERAL, ESCAPES[this]) name = ""
except KeyError: if s.match("<"):
for char in this: while 1:
a(LITERAL, char) char = s.get()
if char is None:
raise error, "unterminated index"
if char == ">":
break
# FIXME: check for valid character
name = name + char
if not name:
raise error, "bad index"
try:
index = int(name)
except ValueError:
try:
index = pattern.groupindex[name]
except KeyError:
raise IndexError, "unknown index"
a((MARK, index))
elif len(this) > 1 and this[1] in DIGITS:
while s.next in DIGITS:
this = this + s.get()
a((MARK, int(this[1:])))
else:
try:
a(ESCAPES[this])
except KeyError:
for char in this:
a((LITERAL, char))
else: else:
a(LITERAL, this) a((LITERAL, this))
return p return p
def expand_template(template, match):
# FIXME: <fl> this is sooooo slow. drop in the slicelist
# code instead
p = []
a = p.append
for c, s in template:
if c is LITERAL:
a(s)
elif c is MARK:
s = match.group(s)
if s is None:
raise error, "empty group"
a(s)
return match.string[:0].join(p)
if __name__ == "__main__": if __name__ == "__main__":
from pprint import pprint from pprint import pprint
from testpatterns import PATTERNS from testpatterns import PATTERNS
@ -548,7 +591,7 @@ if __name__ == "__main__":
except: except:
pass pass
a = a + 1 a = a + 1
except SyntaxError, v: except error, v:
print "**", repr(pattern), v print "**", repr(pattern), v
b = b + 1 b = b + 1
print "-"*68 print "-"*68

File diff suppressed because it is too large Load Diff