[Python-checkins] CVS: python/dist/src/Lib sre.py,1.6,1.7 sre_compile.py,1.4,1.5 sre_constants.py,1.4,1.5 sre_parse.py,1.4,1.5

Fredrik Lundh python-dev@python.org
Thu, 29 Jun 2000 01:58:47 -0700


Update of /cvsroot/python/python/dist/src/Lib
In directory slayer.i.sourceforge.net:/tmp/cvs-serv11309

Modified Files:
	sre.py sre_compile.py sre_constants.py sre_parse.py 
Log Message:
towards 1.6b1

Index: sre.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/sre.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -C2 -r1.6 -r1.7
*** sre.py	2000/06/18 20:27:10	1.6
--- sre.py	2000/06/29 08:58:44	1.7
***************
*** 13,16 ****
--- 13,17 ----
  
  import sre_compile
+ import sre_parse
  
  # flags
***************
*** 21,24 ****
--- 22,32 ----
  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
***************
*** 47,50 ****
--- 55,61 ----
      return _compile(pattern, flags)
  
+ def template(pattern, flags=0):
+     return _compile(pattern, flags|T)
+ 
  def escape(pattern):
      s = list(pattern)
***************
*** 84,91 ****
      return _subn(pattern, template, string, count)[0]
  
- def _expand(match, template):
-     # internal: expand template
-     return template # FIXME
- 
  def _subn(pattern, template, string, count=0):
      # internal: pattern.subn implementation hook
--- 95,98 ----
***************
*** 93,99 ****
          filter = template
      else:
!         # FIXME: prepare template
          def filter(match, template=template):
!             return _expand(match, template)
      n = i = 0
      s = []
--- 100,106 ----
          filter = template
      else:
! 	template = sre_parse.parse_template(template, pattern)
          def filter(match, template=template):
!             return sre_parse.expand_template(template, match)
      n = i = 0
      s = []
***************
*** 109,112 ****
--- 116,121 ----
          append(filter(m))
          i = m.end()
+ 	if i <= j:
+ 	    break
          n = n + 1
      if i < len(string):
***************
*** 127,130 ****
--- 136,141 ----
          append(string[i:j])
          i = m.end()
+ 	if i <= j:
+ 	    break
          n = n + 1
      if i < len(string):

Index: sre_compile.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/sre_compile.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** sre_compile.py	2000/06/01 17:39:12	1.4
--- sre_compile.py	2000/06/29 08:58:44	1.5
***************
*** 49,53 ****
  	    raise
  
! def _compile(code, pattern, flags, level=0):
      append = code.append
      for op, av in pattern:
--- 49,53 ----
  	    raise
  
! def _compile(code, pattern, flags):
      append = code.append
      for op, av in pattern:
***************
*** 71,91 ****
  	    for av in av[1]:
  		skip = len(code); append(0)
! 		_compile(code, av, flags, level)
! 		append(OPCODES[JUMP])
! 		tail.append(len(code)); append(0)
  		code[skip] = len(code) - skip
  	    append(0) # end of branch
! 	    for tail in tail:
  		code[tail] = len(code) - tail
  	elif op is CALL:
  	    append(OPCODES[op])
  	    skip = len(code); append(0)
! 	    _compile(code, av, flags, level+1)
  	    append(OPCODES[SUCCESS])
  	    code[skip] = len(code) - skip
! 	elif op is CATEGORY: # not used by current parser
  	    append(OPCODES[op])
  	    if flags & SRE_FLAG_LOCALE:
  		append(CH_LOCALE[CHCODES[av]])
  	    else:
  		append(CHCODES[av])
--- 71,94 ----
  	    for av in av[1]:
  		skip = len(code); append(0)
! 		_compile(code, av, flags)
! ##		append(OPCODES[SUCCESS])
!  		append(OPCODES[JUMP])
!  		tail.append(len(code)); append(0)
  		code[skip] = len(code) - skip
  	    append(0) # end of branch
!  	    for tail in tail:
  		code[tail] = len(code) - tail
  	elif op is CALL:
  	    append(OPCODES[op])
  	    skip = len(code); append(0)
! 	    _compile(code, av, flags)
  	    append(OPCODES[SUCCESS])
  	    code[skip] = len(code) - skip
! 	elif op is CATEGORY:
  	    append(OPCODES[op])
  	    if flags & SRE_FLAG_LOCALE:
  		append(CH_LOCALE[CHCODES[av]])
+ 	    elif flags & SRE_FLAG_UNICODE:
+ 		append(CH_UNICODE[CHCODES[av]])
  	    else:
  		append(CHCODES[av])
***************
*** 99,104 ****
  	    if flags & SRE_FLAG_IGNORECASE:
  		append(OPCODES[OP_IGNORE[op]])
! 		def fixup(literal):
! 		    return ord(literal.lower())
  	    else:
  		append(OPCODES[op])
--- 102,107 ----
  	    if flags & SRE_FLAG_IGNORECASE:
  		append(OPCODES[OP_IGNORE[op]])
! 		def fixup(literal, flags=flags):
! 		    return _sre.getlower(ord(literal), flags)
  	    else:
  		append(OPCODES[op])
***************
*** 117,120 ****
--- 120,125 ----
  		    if flags & SRE_FLAG_LOCALE:
  			append(CH_LOCALE[CHCODES[av]])
+ 		    elif flags & SRE_FLAG_UNICODE:
+ 			append(CH_UNICODE[CHCODES[av]])
  		    else:
  			append(CHCODES[av])
***************
*** 126,159 ****
  	    if flags & SRE_FLAG_IGNORECASE:
  		append(OPCODES[OP_IGNORE[op]])
- 		append(ord(av.lower()))
  	    else:
  		append(OPCODES[op])
! 		append(ord(av))
  	elif op is MARK:
  	    append(OPCODES[op])
  	    append(av)
   	elif op in (REPEAT, MIN_REPEAT, MAX_REPEAT):
! 	    lo, hi = av[2].getwidth()
!  	    if lo == 0:
!  		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)
  		append(av[0])
  		append(av[1])
! 		_compile(code, av[2], flags, level+1)
  		append(OPCODES[SUCCESS])
  		code[skip] = len(code) - skip
  	    else:
! 		append(OPCODES[op])
! 		skip = len(code); append(0)
! 		append(av[0])
! 		append(av[1])
! 		_compile(code, av[2], flags, level+1)
! 		if op is MIN_REPEAT:
! 		    append(OPCODES[MIN_UNTIL])
  		else:
! 		    append(OPCODES[MAX_UNTIL])
! 		code[skip] = len(code) - skip
  	elif op is SUBPATTERN:
   	    group = av[0]
--- 131,171 ----
  	    if flags & SRE_FLAG_IGNORECASE:
  		append(OPCODES[OP_IGNORE[op]])
  	    else:
  		append(OPCODES[op])
! 	    append(ord(av))
  	elif op is MARK:
  	    append(OPCODES[op])
  	    append(av)
   	elif op in (REPEAT, MIN_REPEAT, MAX_REPEAT):
! 	    if flags & SRE_FLAG_TEMPLATE:
! 		append(OPCODES[REPEAT])
  		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:
! 		lo, hi = av[2].getwidth()
! 		if lo == 0:
! 		    raise error, "nothing to repeat"
! 		if 0 and lo == hi == 1 and op is MAX_REPEAT:
! 		    # FIXME: <fl> need a better way to figure out when
! 		    # it's safe to use this one (in the parser, probably)
! 		    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:
! 		    append(OPCODES[op])
! 		    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:
   	    group = av[0]
***************
*** 161,165 ****
   		append(OPCODES[MARK])
   		append((group-1)*2)
! 	    _compile(code, av[1], flags, level+1)
   	    if group:
   		append(OPCODES[MARK])
--- 173,177 ----
   		append(OPCODES[MARK])
   		append((group-1)*2)
! 	    _compile(code, av[1], flags)
   	    if group:
   		append(OPCODES[MARK])

Index: sre_constants.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/sre_constants.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** sre_constants.py	2000/06/01 17:39:12	1.4
--- sre_constants.py	2000/06/29 08:58:44	1.5
***************
*** 16,19 ****
--- 16,24 ----
  #
  
+ # should this really be here?
+ 
+ class error(Exception):
+     pass
+ 
  # operators
  
***************
*** 31,34 ****
--- 36,40 ----
  IN = "in"
  IN_IGNORE = "in_ignore"
+ INFO = "info"
  JUMP = "jump"
  LITERAL = "literal"
***************
*** 37,43 ****
  MAX_REPEAT = "max_repeat"
  MAX_REPEAT_ONE = "max_repeat_one"
- MAX_UNTIL = "max_until"
  MIN_REPEAT = "min_repeat"
- MIN_UNTIL = "min_until"
  NEGATE = "negate"
  NOT_LITERAL = "not_literal"
--- 43,47 ----
***************
*** 45,48 ****
--- 49,53 ----
  RANGE = "range"
  REPEAT = "repeat"
+ REPEAT_ONE = "repeat_one"
  SUBPATTERN = "subpattern"
  
***************
*** 64,75 ****
  CATEGORY_LINEBREAK = "category_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_NOT_WORD = "category_loc_not_word"
! CATEGORY_LOC_LINEBREAK = "category_loc_linebreak"
! CATEGORY_LOC_NOT_LINEBREAK = "category_loc_not_linebreak"
  
  OPCODES = [
--- 69,82 ----
  CATEGORY_LINEBREAK = "category_linebreak"
  CATEGORY_NOT_LINEBREAK = "category_not_linebreak"
  CATEGORY_LOC_WORD = "category_loc_word"
  CATEGORY_LOC_NOT_WORD = "category_loc_not_word"
! CATEGORY_UNI_DIGIT = "category_uni_digit"
! 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 = [
***************
*** 86,95 ****
      GROUP, GROUP_IGNORE,
      IN, IN_IGNORE,
      JUMP,
      LITERAL, LITERAL_IGNORE,
      MARK,
!     MAX_REPEAT, MAX_UNTIL,
      MAX_REPEAT_ONE,
!     MIN_REPEAT, MIN_UNTIL,
      NOT_LITERAL, NOT_LITERAL_IGNORE,
      NEGATE,
--- 93,103 ----
      GROUP, GROUP_IGNORE,
      IN, IN_IGNORE,
+     INFO,
      JUMP,
      LITERAL, LITERAL_IGNORE,
      MARK,
!     MAX_REPEAT,
      MAX_REPEAT_ONE,
!     MIN_REPEAT,
      NOT_LITERAL, NOT_LITERAL_IGNORE,
      NEGATE,
***************
*** 107,114 ****
      CATEGORY_DIGIT, CATEGORY_NOT_DIGIT, CATEGORY_SPACE,
      CATEGORY_NOT_SPACE, CATEGORY_WORD, CATEGORY_NOT_WORD,
!     CATEGORY_LINEBREAK, CATEGORY_NOT_LINEBREAK, CATEGORY_LOC_DIGIT,
!     CATEGORY_LOC_NOT_DIGIT, CATEGORY_LOC_SPACE,
!     CATEGORY_LOC_NOT_SPACE, CATEGORY_LOC_WORD, CATEGORY_LOC_NOT_WORD,
!     CATEGORY_LOC_LINEBREAK, CATEGORY_LOC_NOT_LINEBREAK
  ]
  
--- 115,123 ----
      CATEGORY_DIGIT, CATEGORY_NOT_DIGIT, CATEGORY_SPACE,
      CATEGORY_NOT_SPACE, CATEGORY_WORD, CATEGORY_NOT_WORD,
!     CATEGORY_LINEBREAK, CATEGORY_NOT_LINEBREAK, CATEGORY_LOC_WORD,
!     CATEGORY_LOC_NOT_WORD, CATEGORY_UNI_DIGIT, CATEGORY_UNI_NOT_DIGIT,
!     CATEGORY_UNI_SPACE, CATEGORY_UNI_NOT_SPACE, CATEGORY_UNI_WORD,
!     CATEGORY_UNI_NOT_WORD, CATEGORY_UNI_LINEBREAK,
!     CATEGORY_UNI_NOT_LINEBREAK
  ]
  
***************
*** 139,159 ****
  
  CH_LOCALE = {
!     CATEGORY_DIGIT: CATEGORY_LOC_DIGIT,
!     CATEGORY_NOT_DIGIT: CATEGORY_LOC_NOT_DIGIT,
!     CATEGORY_SPACE: CATEGORY_LOC_SPACE,
!     CATEGORY_NOT_SPACE: CATEGORY_LOC_NOT_SPACE,
      CATEGORY_WORD: CATEGORY_LOC_WORD,
      CATEGORY_NOT_WORD: CATEGORY_LOC_NOT_WORD,
!     CATEGORY_LINEBREAK: CATEGORY_LOC_LINEBREAK,
!     CATEGORY_NOT_LINEBREAK: CATEGORY_LOC_NOT_LINEBREAK
  }
  
  # flags
! SRE_FLAG_TEMPLATE = 1 # NYI
  SRE_FLAG_IGNORECASE = 2
  SRE_FLAG_LOCALE = 4
  SRE_FLAG_MULTILINE = 8
  SRE_FLAG_DOTALL = 16
! SRE_FLAG_VERBOSE = 32
  
  if __name__ == "__main__":
--- 148,180 ----
  
  CH_LOCALE = {
!     CATEGORY_DIGIT: CATEGORY_DIGIT,
!     CATEGORY_NOT_DIGIT: CATEGORY_NOT_DIGIT,
!     CATEGORY_SPACE: CATEGORY_SPACE,
!     CATEGORY_NOT_SPACE: CATEGORY_NOT_SPACE,
      CATEGORY_WORD: CATEGORY_LOC_WORD,
      CATEGORY_NOT_WORD: CATEGORY_LOC_NOT_WORD,
!     CATEGORY_LINEBREAK: CATEGORY_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
! SRE_FLAG_TEMPLATE = 1
  SRE_FLAG_IGNORECASE = 2
  SRE_FLAG_LOCALE = 4
  SRE_FLAG_MULTILINE = 8
  SRE_FLAG_DOTALL = 16
! SRE_FLAG_UNICODE = 32
! SRE_FLAG_VERBOSE = 64
  
  if __name__ == "__main__":
***************
*** 169,172 ****
--- 190,200 ----
      dump(f, ATCODES, "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()
      print "done"

Index: sre_parse.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/sre_parse.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** sre_parse.py	2000/06/09 14:08:07	1.4
--- sre_parse.py	2000/06/29 08:58:44	1.5
***************
*** 21,26 ****
  from sre_constants import *
  
! # FIXME: should be 65535, but the array module currently chokes on
! # unsigned integers larger than 32767...
  MAXREPEAT = int(2L**(_sre.getcodesize()*8-1))-1
  
--- 21,26 ----
  from sre_constants import *
  
! # FIXME: <fl> should be 65535, but the array module currently chokes
! # on unsigned integers larger than 32767 [fixed in 1.6b1?]
  MAXREPEAT = int(2L**(_sre.getcodesize()*8-1))-1
  
***************
*** 28,32 ****
  REPEAT_CHARS  = "*+?{"
  
! # FIXME: string in tuple tests may explode with if char is unicode :-(
  DIGITS = tuple(string.digits)
  
--- 28,33 ----
  REPEAT_CHARS  = "*+?{"
  
! # FIXME: <fl> string in tuple tests may explode with if char is
! # unicode [fixed in 1.6b1?]
  DIGITS = tuple(string.digits)
  
***************
*** 60,69 ****
  
  FLAGS = {
      "i": SRE_FLAG_IGNORECASE,
      "L": SRE_FLAG_LOCALE,
      "m": SRE_FLAG_MULTILINE,
      "s": SRE_FLAG_DOTALL,
-     "t": SRE_FLAG_TEMPLATE,
      "x": SRE_FLAG_VERBOSE,
  }
  
--- 61,73 ----
  
  FLAGS = {
+     # standard flags
      "i": SRE_FLAG_IGNORECASE,
      "L": SRE_FLAG_LOCALE,
      "m": SRE_FLAG_MULTILINE,
      "s": SRE_FLAG_DOTALL,
      "x": SRE_FLAG_VERBOSE,
+     # extensions
+     "t": SRE_FLAG_TEMPLATE,
+     "u": SRE_FLAG_UNICODE,
  }
  
***************
*** 152,156 ****
  		c = self.string[self.index + 1]
  	    except IndexError:
! 		raise SyntaxError, "bogus escape"
  	    char = char + c
  	self.index = self.index + len(char)
--- 156,160 ----
  		c = self.string[self.index + 1]
  	    except IndexError:
! 		raise error, "bogus escape"
  	    char = char + c
  	self.index = self.index + len(char)
***************
*** 206,210 ****
      except ValueError:
  	pass
!     raise SyntaxError, "bogus escape: %s" % repr(escape)
  
  def _escape(source, escape, state):
--- 210,214 ----
      except ValueError:
  	pass
!     raise error, "bogus escape: %s" % repr(escape)
  
  def _escape(source, escape, state):
***************
*** 242,252 ****
      except ValueError:
  	pass
!     raise SyntaxError, "bogus escape: %s" % repr(escape)
  
  
  def _branch(pattern, items):
  
!     # form a branch operator from a set of items (FIXME: move this
!     # optimization to the compiler module!)
  
      subpattern = SubPattern(pattern)
--- 246,255 ----
      except ValueError:
  	pass
!     raise error, "bogus escape: %s" % repr(escape)
  
  
  def _branch(pattern, items):
  
!     # form a branch operator from a set of items
  
      subpattern = SubPattern(pattern)
***************
*** 333,337 ****
  		    code1 = LITERAL, this
  		else:
! 		    raise SyntaxError, "unexpected end of regular expression"
  		if source.match("-"):
  		    # potential range
--- 336,340 ----
  		    code1 = LITERAL, this
  		else:
! 		    raise error, "unexpected end of regular expression"
  		if source.match("-"):
  		    # potential range
***************
*** 347,353 ****
  			    code2 = LITERAL, this
  			if code1[0] != LITERAL or code2[0] != LITERAL:
! 			    raise SyntaxError, "illegal range"
  			if len(code1[1]) != 1 or len(code2[1]) != 1:
! 			    raise SyntaxError, "illegal range"
  			set.append((RANGE, (code1[1], code2[1])))
  		else:
--- 350,356 ----
  			    code2 = LITERAL, this
  			if code1[0] != LITERAL or code2[0] != LITERAL:
! 			    raise error, "illegal range"
  			if len(code1[1]) != 1 or len(code2[1]) != 1:
! 			    raise error, "illegal range"
  			set.append((RANGE, (code1[1], code2[1])))
  		else:
***************
*** 384,388 ****
  		    hi = lo
  		if not source.match("}"):
! 		    raise SyntaxError, "bogus range"
  		if lo:
  		    min = int(lo)
--- 387,391 ----
  		    hi = lo
  		if not source.match("}"):
! 		    raise error, "bogus range"
  		if lo:
  		    min = int(lo)
***************
*** 391,400 ****
  		# FIXME: <fl> check that hi >= lo!
  	    else:
! 		raise SyntaxError, "not supported"
  	    # figure out which item to repeat
  	    if subpattern:
  		item = subpattern[-1:]
  	    else:
! 		raise SyntaxError, "nothing to repeat"
  	    if source.match("?"):
  		subpattern[-1] = (MIN_REPEAT, (min, max, item))
--- 394,403 ----
  		# FIXME: <fl> check that hi >= lo!
  	    else:
! 		raise error, "not supported"
  	    # figure out which item to repeat
  	    if subpattern:
  		item = subpattern[-1:]
  	    else:
! 		raise error, "nothing to repeat"
  	    if source.match("?"):
  		subpattern[-1] = (MIN_REPEAT, (min, max, item))
***************
*** 419,423 ****
  			    char = source.get()
  			    if char is None:
! 				raise SyntaxError, "unterminated name"
  			    if char == ">":
  				break
--- 422,426 ----
  			    char = source.get()
  			    if char is None:
! 				raise error, "unterminated name"
  			    if char == ">":
  				break
***************
*** 427,437 ****
  		    elif source.match("="):
  			# named backreference
! 			raise SyntaxError, "not yet implemented"
! 
  		    else:
  			char = source.get()
  			if char is None:
! 			    raise SyntaxError, "unexpected end of pattern"
! 			raise SyntaxError, "unknown specifier: ?P%s" % char
  		elif source.match(":"):
  		    # non-capturing group
--- 430,439 ----
  		    elif source.match("="):
  			# named backreference
! 			raise error, "not yet implemented"
  		    else:
  			char = source.get()
  			if char is None:
! 			    raise error, "unexpected end of pattern"
! 			raise error, "unknown specifier: ?P%s" % char
  		elif source.match(":"):
  		    # non-capturing group
***************
*** 440,446 ****
  		    # comment
  		    while 1:
! 			char = source.get()
! 			if char is None or char == ")":
  			    break
  		else:
  		    # flags
--- 442,448 ----
  		    # comment
  		    while 1:
! 			if source.next is None or source.next == ")":
  			    break
+ 			source.get()
  		else:
  		    # flags
***************
*** 466,470 ****
  			b.append(p)
  		    else:
! 			raise SyntaxError, "group not properly closed"
  	    else:
  		while 1:
--- 468,472 ----
  			b.append(p)
  		    else:
! 			raise error, "group not properly closed"
  	    else:
  		while 1:
***************
*** 472,476 ****
  		    if char is None or char == ")":
  			break
! 		# FIXME: skip characters?
  
  	elif this == "^":
--- 474,478 ----
  		    if char is None or char == ")":
  			break
! 		    raise error, "unknown extension"
  
  	elif this == "^":
***************
*** 485,489 ****
  
  	else:
! 	    raise SyntaxError, "parser error"
  
      return subpattern
--- 487,491 ----
  
  	else:
! 	    raise error, "parser error"
  
      return subpattern
***************
*** 500,504 ****
  	    b.append(p)
  	elif tail == ")":
! 	    raise SyntaxError, "unbalanced parenthesis"
  	elif tail is None:
  	    if b:
--- 502,506 ----
  	    b.append(p)
  	elif tail == ")":
! 	    raise error, "unbalanced parenthesis"
  	elif tail is None:
  	    if b:
***************
*** 507,514 ****
  	    break
  	else:
! 	    raise SyntaxError, "bogus characters at end of regular expression"
      return p
  
! def parse_replacement(source, pattern):
      # parse 're' replacement string into list of literals and
      # group references
--- 509,516 ----
  	    break
  	else:
! 	    raise error, "bogus characters at end of regular expression"
      return p
  
! def parse_template(source, pattern):
      # parse 're' replacement string into list of literals and
      # group references
***************
*** 521,533 ****
  	    break # end of replacement string
  	if this and this[0] == "\\":
! 	    try:
! 		a(LITERAL, ESCAPES[this])
! 	    except KeyError:
! 		for char in this:
! 		    a(LITERAL, char)
  	else:
! 	    a(LITERAL, this)
      return p
  
  if __name__ == "__main__":
      from pprint import pprint
--- 523,576 ----
  	    break # end of replacement string
  	if this and this[0] == "\\":
! 	    if this == "\\g":
! 		name = ""
! 		if s.match("<"):
! 		    while 1:
! 			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:
! 	    a((LITERAL, this))
      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__":
      from pprint import pprint
***************
*** 549,553 ****
  		pass
  	    a = a + 1
! 	except SyntaxError, v:
  	    print "**", repr(pattern), v
  	b = b + 1
--- 592,596 ----
  		pass
  	    a = a + 1
! 	except error, v:
  	    print "**", repr(pattern), v
  	b = b + 1