Author: pmichaud
Date: Sat May  7 06:12:28 2005
New Revision: 8000

Modified:
   trunk/compilers/pge/PGE/Exp.pir
   trunk/compilers/pge/PGE/Match.pir
   trunk/compilers/pge/PGE/P6Rule.pir
   trunk/config/gen/makefiles/pge.in
   trunk/runtime/parrot/library/PGE/Dumper.pir
   trunk/t/p6rules/capture.t
Log:
Lots of updates:

Added capture aliases.
Added backreferences.
Fixed a bug with nested captures.
Added new tests for backreferences, nested captures, aliases.
Modified creation of PGE.pbc file.


Modified: trunk/compilers/pge/PGE/Exp.pir
==============================================================================
--- trunk/compilers/pge/PGE/Exp.pir     (original)
+++ trunk/compilers/pge/PGE/Exp.pir     Sat May  7 06:12:28 2005
@@ -11,6 +11,7 @@
     PGE::Start     - start of rule
     PGE::End       - (successful) end of rule
     PGE::Literal   - match a literal string
+    PGE::Scalar    - match a scalar
     PGE::Dot       - match any character
     PGE::CCShortcut - character class shortcuts (\d, \D, \w, etc.)
     PGE::Anchor    - matching of ^, ^^, $, $$, \b, \B anchors
@@ -39,6 +40,7 @@
     $P0 = subclass expclass, "PGE::Exp::Start"
     $P0 = subclass expclass, "PGE::Exp::End"
     $P0 = subclass expclass, "PGE::Exp::Literal"
+    $P0 = subclass expclass, "PGE::Exp::Scalar"
     $P0 = subclass expclass, "PGE::Exp::Dot"
     $P0 = subclass expclass, "PGE::Exp::CCShortcut"
     $P0 = subclass expclass, "PGE::Exp::Anchor"
@@ -136,14 +138,16 @@
     .return ($S0)
 .end
 
-=item C<analyze(PMC next, int isarray)>
+=item C<analyze(PMC next, PMC pad)>
 
 The analyze method is used to walk an expression tree and perform
 a variety of optimizations and pre-processing in preparation for
 generating the rule code.  The C<next> parameter identifies the
-expression that will come after this one.  The C<isarray> parameter 
-indicates if capture objects will produce an array of captures or a single
-capture.
+expression that will come after this one.  The C<pad> parameter
+is a work pad hash that is carried from one object to the next.
+Typical entries in the pad include:
+    isarray: does this (group) object cause its subelements to repeat?
+    reps: a hash of lexically repeated capture names
 
 =cut
 
@@ -314,14 +318,14 @@
   greedy:
     emit(code, "    rep = 0")
     unless isgreedy goto lazy
-    emit(code, "  %s_1:", label)
-    emit(code, "    if rep >= %d goto %s_2", max, label)
+    emit(code, "  %s_lit1:", label)
+    emit(code, "    if rep >= %d goto %s_lit2", max, label)
     emit(code, "    $S0 = substr target, pos, litlen")
-    emit(code, "    if $S0 != lit goto %s_2", label)
+    emit(code, "    if $S0 != lit goto %s_lit2", label)
     emit(code, "    inc rep")
     emit(code, "    pos += litlen")
-    emit(code, "    goto %s_1", label)
-    emit(code, "  %s_2:", label)
+    emit(code, "    goto %s_lit1", label)
+    emit(code, "  %s_lit2:", label)
     emit(code, "    if rep < %d goto fail", min)
     unless iscut goto greedy_1
     emit(code, "    goto %s", next)
@@ -330,12 +334,12 @@
     self.emitsub(code, next, "pos", "rep", "litlen")
     emit(code, "    dec rep")
     emit(code, "    pos -= litlen")
-    emit(code, "    goto %s_2", label)
+    emit(code, "    goto %s_lit2", label)
     .return()
 
   lazy:
-    emit(code, "  %s_1:", label)
-    emit(code, "    if rep < %d goto %s_2", min, label)
+    emit(code, "  %s_lit1:", label)
+    emit(code, "    if rep < %d goto %s_lit2", min, label)
     unless iscut goto lazy_1
     emit(code, "    goto %s", next)
     goto lazy_2
@@ -343,22 +347,23 @@
     emit(code, "    if rep >= %d goto %s", max, next)
     self.emitsub(code, next, "pos", "rep", "lit", "litlen")
   lazy_2:
-    emit(code, "  %s_2:", label)
+    emit(code, "  %s_lit2:", label)
     emit(code, "    $S0 = substr target, pos, litlen")
     emit(code, "    if $S0 != lit goto fail")
     emit(code, "    inc rep")
     emit(code, "    pos += litlen")
-    emit(code, "    goto %s_1", label)
+    emit(code, "    goto %s_lit1", label)
 .end
 
 .namespace [ "PGE::Exp::Start" ]
 
 .sub analyze method
     .param pmc next
-    .param int isarray
+    .param pmc pad
+    pad = new Hash                                 # create a new workpad
     $P0 = self["exp1"]
-    $P0.analyze(self, isarray)
-    self.firstchars($P0)
+    $P0.analyze(self, pad)                         # analyze our subexp
+    self.firstchars($P0)                           # set firstchars
 .end
 
 .sub "gen" method
@@ -450,7 +455,7 @@
 
 .sub "analyze" method
     .param pmc next
-    .param int isarray
+    .param pmc pad
     $S0 = self["literal"]                          # set up firstchars
     $S0 = substr $S0, 0, 1
     self["firstchars"] = $S0
@@ -473,6 +478,43 @@
     self.genliteral(code, label, next)
 .end
 
+
+.namespace [ "PGE::Exp::Scalar" ]
+
+.sub "gen" method
+    .param pmc code
+    .param string label
+    .param string next
+    .local pmc emit
+    .local pmc cname
+    .local int subp
+    emit = find_global "PGE::Exp", "emit"
+    $S0 = self."quant"()
+    cname = self["cname"]
+    $I0 = isa cname, "Integer"
+    unless $I0 goto named
+    subp = cname
+    emit(code, "\n  %s:  # backref $%d %s", label, subp, $S0)
+    emit(code, "    lit = ''")
+    emit(code, "    $P0 = getattribute mob, \"PGE::Match\\x0@:capt\"")
+    emit(code, "    isnull $P0, %s_1", label)
+    emit(code, "    $P1 = $P0[%d]", subp)
+    emit(code, "    lit = $P1[-1]")
+    emit(code, "  %s_1:", label)
+    .return self.genliteral(code, label, next)
+  named:
+    $S1 = cname
+    emit(code, "\n  %s:  # backref $<%s> %s", label, subp, $S1)
+    emit(code, "    lit = ''")
+    emit(code, "    $P0 = getattribute mob, \"PGE::Match\\x0%:capt\"")
+    emit(code, "    isnull $P0, %s_1", label)
+    emit(code, "    $P1 = $P0[\"%s\"]", $S1)       # XXX: quote $S1
+    emit(code, "    lit = $P1[-1]")
+    emit(code, "  %s_1:", label)
+    .return self.genliteral(code, label, next)
+.end
+
+
 .namespace [ "PGE::Exp::Dot" ]
 
 .sub "gen" method
@@ -593,7 +635,7 @@
 
 .sub "analyze" method
     .param pmc next
-    .param int isarray 
+    .param pmc pad
     self.firstchars(next)
 .end
 
@@ -646,12 +688,12 @@
 
 .sub "analyze" method
     .param pmc next
-    .param int isarray
+    .param pmc pad
     .local pmc exp1, exp2
     exp2 = self["exp2"]
-    exp2.analyze(next, isarray)
+    exp2.analyze(next, pad)
     exp1 = self["exp1"]
-    exp1.analyze(exp2, isarray)
+    exp1.analyze(exp2, pad)
     self.firstchars(exp1)
 .end
    
@@ -675,7 +717,7 @@
 
 .sub "analyze" method
     .param pmc next
-    .param int isarray
+    .param int pad
     self.firstchars(next)
 .end
 
@@ -702,12 +744,17 @@
 
 .sub "analyze" method
     .param pmc next
-    .param int isarray
+    .param pmc pad
     .local pmc exp1, exp2
+    .local pmc creps
+
+    creps = pad["creps"]
+    creps = clone creps
     exp1 = self["exp1"]
     exp2 = self["exp2"]
-    exp1.analyze(next, isarray)
-    exp2.analyze(next, isarray)
+    exp2.analyze(next, pad)
+    pad["creps"] = creps
+    exp1.analyze(next, pad)
     self.firstchars(exp1, exp2)
 .end
 
@@ -734,28 +781,60 @@
 
 .sub "analyze" method
     .param pmc next
-    .param int isarray
+    .param pmc pad
     .local pmc exp1
-
-    self["firstchars"] = ""
-    $I0 = self["isarray"]                          # see if this is an array
-    isarray |= $I0
+    .local int isarray
+    .local pmc creps
+    .local string cname
+
+    self["firstchars"] = ""                        # no firstchars default
+
+    $I0 = exists pad["creps"]                      # create creps hash array
+    if $I0 goto creps_1                            # if not exists
+    $P0 = new Hash
+    pad["creps"] = $P0
+  creps_1:
+    creps = pad["creps"]                           # load creps hash
+    $I0 = exists self["cname"]
+    unless $I0 goto isarray_0                      # skip if no capture
+    $P0 = self["cname"]
+    cname = $P0
+    cname = concat "%", cname
+    $I0 = isa $P0, "Integer"                       # Integer = subpattern cap
+    if $I0 goto creps_2
+  creps_2:
+    $I0 = exists creps[cname]                      # have seen capture name?
+    unless $I0 goto creps_3                        #
+    $P0 = creps[cname]                             # yes, so prev is now 
+    $P0["isarray"] = 1                             # an array capture
+    self["isarray"] = 1                            # and so is self
+  creps_3:
+    creps[cname] = self                            # mark us for future ref
+
+  isarray_0:
+    isarray = pad["isarray"]                       # set group's isarray
+    $I0 = self["isarray"]                          # and pass along to
+    isarray |= $I0                                 # nested objects
     self["isarray"] = isarray
     $I0 = self["cscope"]
     unless $I0 goto isarray_1
-    isarray = 0
+    isarray = 0                                    # each capt obj is single
+    delete pad["creps"]                            # new lexical name scope
   isarray_1:
     $I0 = defined self["exp1"]
     unless $I0 goto end
     exp1 = self["exp1"]
-    exp1.analyze(next, isarray)
+    pad["isarray"] = isarray
+    exp1.analyze(next, pad)
+  fc:
     $I0 = self["min"]                              # set up firstchars
-    if $I0 > 0 goto isarray_2
+    if $I0 > 0 goto fc_2
     self.firstchars(exp1, next)
     goto end
-  isarray_2:
+  fc_2:
     self.firstchars(exp1)
   end:
+    pad["creps"] = creps
 .end
  
 .sub "gen" method
@@ -831,8 +910,9 @@
     emit(code, "    $P0 = pop gpad")
     emit(code, "    $P0 = pop cpad")
     unless iscapture goto init_2
-    emit(code, "    unless iscreator goto fail")
+    emit(code, "    unless iscreator goto %s_i4", label)
     emit(code, "    delete cobcapt[%s]", captname)
+    emit(code, "  %s_i4:", label)
   init_2:
     emit(code, "    if cutting != 1 goto fail")
     emit(code, "    cutting = 0")
@@ -910,7 +990,9 @@
     emit(code, "    cpad[-1] = $P0")
   subpat_2:
     emit(code, "    push capt, $P0")
+    emit(code, "    save capt")
     emit(code, "    bsr %s_s1", sublabel)
+    emit(code, "    restore capt")
     emit(code, "    $P0 = pop capt")
     emit(code, "    ret")
     exp1 = self["exp1"]

Modified: trunk/compilers/pge/PGE/Match.pir
==============================================================================
--- trunk/compilers/pge/PGE/Match.pir   (original)
+++ trunk/compilers/pge/PGE/Match.pir   Sat May  7 06:12:28 2005
@@ -191,8 +191,8 @@
     .param string b2
     .local pmc capt
     .local int spi, spc
+    .local pmc iter
     .local string prefix1, prefix2
-    .local int matchidx
     unless argcS < 3 goto start
     b2 = "]"
     unless argcS < 2 goto start
@@ -208,6 +208,7 @@
     $I0 = self."from"()
     print $I0
     print "> "
+
   subpats:
     $I0 = self
     print $I0
@@ -222,7 +223,11 @@
     $S0 = spi
     concat prefix1, $S0
     concat prefix1, b2
+    $I0 = defined capt[spi]
+    unless $I0 goto subpats_3
     $P0 = capt[spi]
+    $I0 = defined $P0
+    unless $I0 goto subpats_3
     $I0 = 0
     $I1 = elements $P0
     unless $I0 < $I1 goto subpats_3
@@ -244,7 +249,40 @@
   subpats_3:
     inc spi
     goto subpats_1
+
   subrules:
+    capt = getattribute self, "PGE::Match\x0%:capt"
+    isnull capt, end
+    iter = new Iterator, capt
+    iter = 0
+  subrules_1:
+    unless iter goto end
+    $S0 = shift iter
+    prefix1 = concat prefix, "<"
+    concat prefix1, $S0
+    concat prefix1, ">"
+    $I0 = defined capt[$S0]
+    unless $I0 goto subrules_1
+    $P0 = capt[$S0]
+    $I0 = 0
+    $I1 = elements $P0
+    unless $I0 < $I1 goto subrules_1
+    $P1 = getprop "isarray", $P0
+    if $P1 goto subrules_2
+    $P1 = $P0[-1]
+    $P1."dump"(prefix1, b1, b2)
+    goto subrules_1
+  subrules_2:
+    unless $I0 < $I1 goto subrules_1
+    $P1 = $P0[$I0]
+    prefix2 = concat prefix1, b1
+    $S0 = $I0
+    concat prefix2, $S0
+    concat prefix2, b2
+    $P1."dump"(prefix2, b1, b2)
+    inc $I0
+    goto subrules_2
+  end:
 .end
 
 =head1 AUTHOR

Modified: trunk/compilers/pge/PGE/P6Rule.pir
==============================================================================
--- trunk/compilers/pge/PGE/P6Rule.pir  (original)
+++ trunk/compilers/pge/PGE/P6Rule.pir  Sat May  7 06:12:28 2005
@@ -54,6 +54,17 @@
     p6meta[']'] = u
     p6meta['('] = $P0
     p6meta[')'] = u
+    $P0 = find_global "PGE::P6Rule", "p6rule_parse_alias"
+    p6meta['$<'] = $P0
+    p6meta['$1'] = $P0
+    p6meta['$2'] = $P0
+    p6meta['$3'] = $P0
+    p6meta['$4'] = $P0
+    p6meta['$5'] = $P0
+    p6meta['$6'] = $P0
+    p6meta['$7'] = $P0
+    p6meta['$8'] = $P0
+    p6meta['$9'] = $P0
     # $P0 = find_global "PGE::P6Rule", "p6rule_parse_assert"      # XXX: TODO
     # p6meta['<'] = $P0
     # p6meta['>'] = u
@@ -85,6 +96,10 @@
     plen = lex["plen"]
     pos = lex["pos"]
     pos += skip                      
+    lex["ws"] = 0
+    unless pos < plen goto end
+    $I0 = is_whitespace pattern, pos
+    lex["ws"] = $I0
   skipws:
     unless pos < plen goto end
     $I0 = is_whitespace pattern, pos 
@@ -105,6 +120,44 @@
     .return (pos)
 .end
 
+=item C<p6rule_parse_string(STR pattern, PMC lex, STR stopat)>
+
+Grab a sequence of characters, processing backslash escapes,
+until one of the characters in C<stopat> is found.  Advances
+the C<lex["pos"]> pointer as it goes.
+
+=cut
+
+.sub p6rule_parse_string
+    .param string pattern
+    .param pmc lex
+    .param string stopat
+    .param int pos
+    .param int plen
+    .param string val
+    pos = lex["pos"]
+    plen = lex["plen"]
+    val = ""
+  string_1:
+    unless pos < plen goto end
+    $S0 = substr pattern, pos, 1
+    unless $S0 == "\\" goto string_2
+    inc pos
+    unless pos < plen goto end
+    $S0 = substr pattern, pos, 1
+    goto string_3
+  string_2:
+    $I0 = index stopat, $S0
+    if $I0 >= 0 goto end
+  string_3:
+    concat val, $S0
+    inc pos
+    goto string_1
+  end:
+    lex["pos"] = pos
+    .return (val)
+.end
+    
 =item C<p6rule_parse_error(STR pattern, PMC lex, STR message)>
 
 Generates error messages during parsing.  Gracefully recovering
@@ -209,7 +262,6 @@
     $P0 = find_global "PGE::Exp", "new"
     exp = $P0("PGE::Exp::Anchor")
     exp["token"] = token
-    if token != '^' goto end
   end:
     .return (exp)
 .end
@@ -231,34 +283,41 @@
     .local int pos
     .local string ket
     .local int subp
-    p6rule_parse_skip(pattern, lex, $I0)
-    $P0 = find_global "PGE::Exp", "new"
+    .local pmc cname
+    .local int isaliased
+
+    p6rule_parse_skip(pattern, lex, 1)             # skip '(' or ']'
+    $P0 = find_global "PGE::Exp", "new"            # create group exp object
     exp = $P0("PGE::Exp::Group")
-    if token == '(' goto group_1
-    ket = ']'
-    goto group_2
+    isaliased = exists lex["cname"]
+    unless isaliased goto group_1                  # are we aliased?
+    cname = lex["cname"]                           # yes, use that capture name
+    exp["cname"] = cname
+    delete lex["cname"]                            # and then remove it
   group_1:
-    ket = ')'
-    subp = lex["subp"]
-    exp["cname"] = subp
-    exp["cscope"] = 1
-    lex["subp"] = 0
+    subp = lex["subp"]                             # current subpattern count
+    unless token == '(' goto group_2               
+    exp["cscope"] = 1                              # '(' == scoped capture
+    lex["subp"] = 0                                # restart subpattern #'s
+    if isaliased goto group_2                      # if not aliased
+    exp["cname"] = subp                            # use subpattern number
+    inc subp                                       # and increase
   group_2:
-    $P1 = "p6rule_parse_exp"(pattern, lex)
-    exp["exp1"] = $P1
-    pos = lex['pos']
-    $S0 = substr pattern, pos, 1
-    if $S0 != ket goto error
-    p6rule_parse_skip(pattern, lex, 1)
-    unless token == '(' goto end
-    inc subp
-    lex["subp"] = subp
+    $P1 = "p6rule_parse_exp"(pattern, lex)         # parse subexpression
+    exp["exp1"] = $P1                              # store in group exp
+    pos = lex['pos']                               # update pattern pos
+    $S0 = substr pattern, pos, 1                   # get closing char
+    unless token == '(' goto group_3               # if scoped capture '('
+    lex["subp"] = subp                             # set next subpattern #
+    if $S0 == ')' goto group_4                     # check for closing char
+    p6rule_parse_error(pattern, lex, "group missing ')'")
     goto end
-  error:
-    $S0 = "missing '"
-    concat $S0, ket
-    concat $S0, "'"
-    p6rule_parse_error(pattern, lex, $S0)
+  group_3:                                         # unscoped capture
+    if $S0 == ']' goto group_4                     
+    p6rule_parse_error(pattern, lex, "group missing ']'")
+    goto end
+  group_4:
+    p6rule_parse_skip(pattern, lex, 1)             # skip closing token
   end:
     .return (exp)
 .end
@@ -304,6 +363,66 @@
     .return (exp)
 .end
 
+=item C<p6rule_parse_alias(STR pattern, PMC lex, STR token)>
+
+Parse an alias or backreference.
+
+=cut
+
+.sub p6rule_parse_alias
+    .param string pattern
+    .param pmc lex
+    .param string token
+    .local int pos, plen
+    .local int subp
+    .local pmc exp
+   
+
+    pos = lex["pos"]                               # get current position
+    inc pos                                        # skip past '$'
+    if token == '$<' goto name                     # $< == named capture
+    $I0 = pos                                      # aha, numeric capture
+    plen = lex["plen"]                             # now let's scan for digits
+  num_0:
+    if $I0 >= plen goto num_1            
+    $I1 = is_digit pattern, $I0
+    unless $I1 goto num_1
+    inc $I0
+    goto num_0
+  num_1:                                           # we have digits
+    lex["pos"] = $I0                               # save new scan position
+    $I0 -= pos                                     # get length of digit seq.
+    $S0 = substr pattern, pos, $I0                 # extract digit seq.
+    subp = $S0                                     # convert to integer
+    lex["subp"] = subp                             # store next subpattern #
+    dec subp                                       # compute index of
+    lex["cname"] = subp                            # this capture
+    p6rule_parse_skip(pattern, lex, 0)             # skip ws
+    goto alias
+  name:
+    inc pos                                        # skip over '<'
+    lex["pos"] = pos                               # set position
+    $S0 = p6rule_parse_string(pattern, lex, '>')   # now get named alias
+    lex["cname"] = $S0                             # capture to this alias
+    p6rule_parse_skip(pattern, lex, 1)             # skip closing '>'  (XXX)
+  alias:
+    pos = lex["pos"]                               # get current pos
+    $S0 = substr pattern, pos, 2                   # check for ':='
+    unless $S0 == ':=' goto backref                
+    p6rule_parse_skip(pattern, lex, 2)             # skip ':='
+    exp = p6rule_parse_term(pattern, lex)          # parse a term to capture
+    goto end
+  backref:
+    $P0 = find_global "PGE::Exp", "new"            # create a backreference
+    exp = $P0("PGE::Exp::Scalar")
+    $P0 = lex["cname"]
+    exp["cname"] = $P0
+  end:
+    delete lex["cname"]                            # destroy any capture name
+    .return (exp)
+.end
+
+
 =item C<p6rule_parse_charclass(STR pattern, PMC lex)>
 
 Parses a character class of some sort, including the \n, \N, \s, \S,
@@ -606,7 +725,7 @@
     exp = $P1("PGE::Exp::Concat", exp, $P2)
     exp = $P1("PGE::Exp::Start", exp)
 
-    exp.analyze(0)
+    exp.analyze()
     exp.serno(0)
 
     code = new String

Modified: trunk/config/gen/makefiles/pge.in
==============================================================================
--- trunk/config/gen/makefiles/pge.in   (original)
+++ trunk/config/gen/makefiles/pge.in   Sat May  7 06:12:28 2005
@@ -17,7 +17,7 @@
        $(CP) PGE.pbc $(PARROT_LIBRARY)
 
 PGE.pbc: PGE.pir PGE/Exp.pir PGE/Match.pir PGE/P6Rule.pir PGE/TokenHash.pir
-       $(PARROT) --output-pbc PGE.pir >PGE.pbc
+       $(PARROT) -o PGE.pbc --output-pbc PGE.pir 
 
 # This is a listing of all targets, that are meant to be called by users
 help:

Modified: trunk/runtime/parrot/library/PGE/Dumper.pir
==============================================================================
--- trunk/runtime/parrot/library/PGE/Dumper.pir (original)
+++ trunk/runtime/parrot/library/PGE/Dumper.pir Sat May  7 06:12:28 2005
@@ -57,6 +57,21 @@
     print "\n"
 .end
 
+.namespace [ "PGE::Exp::Scalar" ]
+
+.sub "dump" method
+    .param int indent
+    .local pmc cname
+    cname = self["cname"]
+    self."dumpindent"(indent)
+    print "BACKREF �"
+    print cname
+    print "� "
+    $S0 = self."quant"()
+    print $S0
+    print "\n"
+.end
+
 .namespace [ "PGE::Exp::Dot" ]
 
 .sub "dump" method

Modified: trunk/t/p6rules/capture.t
==============================================================================
--- trunk/t/p6rules/capture.t   (original)
+++ trunk/t/p6rules/capture.t   Sat May  7 06:12:28 2005
@@ -13,13 +13,54 @@
 p6rule_like('abcd', '(a(b(c))(d))', qr/mob 0 0 0: <c @ 2>/, 'nested match');
 p6rule_like('abcd', '(a(b(c))(d))', qr/mob 0 1: <d @ 3>/, 'nested match');
 
-# backreferences not implemented yet
-#p6rule_is  ('bookkeeper', '(((.)$3)+)', 'backreference');
-#p6rule_like('bookkeeper', '(((.)$3)+)', 
-#            qr/0: <ookkee @ 1>/, 'backref $0');
-#p6rule_like('bookkeeper', '(((.)$3)+)', 
-#            qr/1: <ookkee @ 1>/, 'backref $1');
-#p6rule_like('bookkeeper', '(((.)$3)+)', 
-#            qr/2: <oo @ 1> <kk @ 3> <ee @ 5>/, 'backref $2');
-#p6rule_like('bookkeeper', '(((.)$3)+)', 
-#            qr/3: <o @ 1> <k @ 3> <e @ 5>/, 'backref $2');
+p6rule_like('abcdefg', '(a) [ (bc) (d) | .* (ef) ] .* (g)',
+            qr/mob 0: <a @ 0>/, 'alt subpattern before group');
+p6rule_like('abcdefg', '(a) [ (bc) (d) | .* (ef) ] .* (g)',
+            qr/mob 1: <bc @ 1>/, 'alt subpattern in group');
+p6rule_like('abcdefg', '(a) [ (bc) (d) | .* (ef) ] .* (g)',
+            qr/mob 2: <d @ 3>/, 'alt subpattern in group');
+p6rule_like('abcdefg', '(a) [ (bc) (d) | .* (ef) ] .* (g)',
+            qr/mob 3: <g @ 6>/, 'alt subpattern after group');
+p6rule_like('abcdefg', '(a) [ (bc) (x) | .* (ef) ] .* (g)',
+            qr/mob 1: <ef @ 4>/, '2nd alt subpattern in group');
+p6rule_like('abcdefg', '(a) [ (bc) (x) | .* (ef) ] .* (g)',
+            qr/mob 3: <g @ 6>/, '2nd alt subpattern after group');
+
+p6rule_like('abc', '( (.) )*', qr/mob 0 1 0: <b @ 1>/,
+            'nested repeated captures');
+p6rule_like('abc', '[ (.) ]*', qr/mob 0 1: <b @ 1>/,
+            'nested repeated captures');
+p6rule_like('abc', '( [.] )*', qr/mob 0 1: <b @ 1>/,
+            'nested repeated captures');
+
+p6rule_like('abcdefg', '(.) (.) $7:=(.) (.) $4:=(.)', qr/mob 0: <a @ 0>/,
+            'numbered aliases $1');
+p6rule_like('abcdefg', '(.) (.) $7:=(.) (.) $4:=(.)', qr/mob 1: <b @ 1>/,
+            'numbered aliases $2');
+p6rule_like('abcdefg', '(.) (.) $7:=(.) (.) $4:=(.)', qr/mob 6: <c @ 2>/,
+            'numbered aliases $7');
+p6rule_like('abcdefg', '(.) (.) $7:=(.) (.) $4:=(.)', qr/mob 7: <d @ 3>/,
+            'numbered aliases $8');
+p6rule_like('abcdefg', '(.) (.) $7:=(.) (.) $4:=(.)', qr/mob 3: <e @ 4>/,
+            'numbered aliases $4');
+
+
+p6rule_like('abcdefg', '$1:=[ (.) (.) (.) ] (.)', qr/mob 0: <abc @ 0>/,
+            'perl5 numbered captures $1');
+p6rule_like('abcdefg', '$1:=[ (.) (.) (.) ] (.)', qr/mob 1: <a @ 0>/,
+            'perl5 numbered captures $1');
+p6rule_like('abcdefg', '$1:=[ (.) (.) (.) ] (.)', qr/mob 2: <b @ 1>/,
+            'perl5 numbered captures $1');
+p6rule_like('abcdefg', '$1:=[ (.) (.) (.) ] (.)', qr/mob 3: <c @ 2>/,
+            'perl5 numbered captures $1');
+p6rule_like('abcdefg', '$1:=[ (.) (.) (.) ] (.)', qr/mob 4: <d @ 3>/,
+            'perl5 numbered captures $1');
+
+p6rule_is  ('bookkeeper', '[(.)$1]+', 'backreference');
+p6rule_like('bookkeeper', '[(.)$1]+', 
+            qr/mob 0 0: <o @ 1>/, 'backref $1');
+p6rule_like('bookkeeper', '[(.)$1]+', 
+            qr/mob 0 1: <k @ 3>/, 'backref $1');
+p6rule_like('bookkeeper', '[(.)$1]+', 
+            qr/mob 0 2: <e @ 5>/, 'backref $1');
+

Reply via email to