home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _9c9ea2add23b28a70a6cbc263740511b < prev    next >
Encoding:
Text File  |  2004-06-01  |  20.1 KB  |  678 lines

  1. package ActiveState::Rx::Info;
  2.  
  3. use ActiveState::Rx;
  4.  
  5. our $VERSION = 0.10;
  6.  
  7. #=============================================================================
  8. # The following subs are the API, accessed from clients.
  9. #=============================================================================
  10. sub new {
  11.   my $class = shift;
  12.   my $regex = shift || "";
  13.   my $mods = shift  || "";
  14.  
  15.   my $o = bless { regex  => $regex,
  16.                   mods   => $mods,
  17.                 }, $class;
  18.  
  19.   $o->{global} = 1 if ($mods =~ s/g//);
  20.   $o->{cregex} = eval qq|qr{$regex}$mods|;
  21.   $o->{uregex} = ActiveState::Rx::rxdump($regex,$mods);
  22.   $o->{tregex} = ActiveState::Rx::translate_tree($o->{uregex}, 0);
  23.   $o->_sort_ranges;
  24.   $o->_count_groups;
  25.   return $o;
  26. }
  27.  
  28. sub regex {
  29.   my $o = shift;
  30.   return $o->{regex};
  31. }
  32.  
  33. sub modifiers {
  34.   my $o = shift;
  35.   return $o->{mods}
  36. }
  37.  
  38. sub groupCount {
  39.   my $o = shift;
  40.   return scalar keys %{$o->{groups}};
  41. }
  42.  
  43. sub maxLevel {
  44.   my $o = shift;
  45.   my $nodeId = shift;
  46.   return 0;
  47. }
  48.  
  49. sub match {
  50.   my $o = shift;
  51.   my $target = shift;
  52.   return $o->_multimatch($target)
  53.     if $o->{global};
  54.   return $o->_match($target);
  55. }
  56.  
  57. my %tips;
  58. sub nodeTip {
  59.   my $o = shift;
  60.   my $nodeID = shift;
  61.  
  62.   my $regex = $o->{regex};
  63.   my $modifiers = $o->{mods};  
  64.   my $uregex = $o->{uregex};
  65.  
  66.   do {
  67.     my $n = $uregex->{$nodeID};
  68.     my $i = $nodeID;
  69.     my $h = $uregex;
  70.     my $r = $regex;
  71.     my $m = $modifiers;
  72.     @_ = ($o, $n, $i, $h, $r, $m); # If a sub is called, it gets all these.
  73.     return eval $tips{$uregex->{$nodeID}{TYPE}};
  74.   };
  75. }
  76.  
  77. sub nodeRange {
  78.   my $o = shift;
  79.   my $id = shift;
  80.   my $level = shift;
  81.   my @ret;
  82.  
  83.   return unless $id ne "";
  84.  
  85.   my @offsets = @{$o->{uregex}{OFFSETS}};
  86.   my @lengths = @{$o->{uregex}{LENGTHS}};
  87.   
  88.   if (defined $offsets[$id] and defined $lengths[$id]) {
  89.     my $start = $offsets[$id] - 1;
  90.     my $end = $start + $lengths[$id] - 1;    
  91.     push @ret, $start, $end;
  92.   }
  93.  
  94.   return wantarray ? @ret : \@ret;
  95. }
  96.  
  97. sub childNodesRange {
  98.   my $o = shift;
  99.   my $id = shift;
  100.   my @ret;
  101.  
  102.   my $node = $o->get_tnode($id);
  103.  
  104.   if ($node->{CHILD}) {
  105.     my @children = @{$node->{CHILD}};
  106.     
  107.     # max and min are first set to an extremely large number.
  108.     my $max = -1;
  109.     my $min = -1;
  110.     
  111.     # find the span of the child nodes
  112.     for my $child (@children) {
  113.       my $child_id = $child->{__this__};
  114.       my @child_span = $o->nodeRange($child_id, 0);
  115.       $min = $child_span[0]
  116.         if $child_span[0] < $min || $min == -1;
  117.       $max = $child_span[1]
  118.         if $child_span[1] > $max || $max == -1;
  119.     }
  120.     push @ret, $min, $max;
  121.   }
  122.   
  123.   # The children of a '(' or ')' are everything in between the
  124.   # parens 
  125.   elsif ($node->{TYPE} eq 'OPEN') {
  126.     # Find the corresponding CLOSE node 
  127.     my $which = $node->{ARGS};
  128.     my $close = $o->find_tnode(TYPE => 'CLOSE', ARGS => $which);
  129.     my $close_id = $close->{__this__};
  130.     my (undef,$opn) = $o->nodeRange($id, 0);
  131.     my ($cls,undef) = $o->nodeRange($close_id, 0);
  132.     push @ret, $opn + 1, $cls - 1;
  133.   }
  134.   elsif ($node->{TYPE} eq 'CLOSE') {
  135.     # Find the corresponding OPEN node 
  136.     my $which = $node->{ARGS};
  137.     my $open = $o->find_tnode(TYPE => 'OPEN', ARGS => $which);
  138.     my $open_id = $open->{__this__};
  139.     my (undef,$opn) = $o->nodeRange($open_id, 0);
  140.     my ($cls,undef) = $o->nodeRange($id, 0);
  141.     push @ret, $opn + 1, $cls - 1;
  142.   }
  143.  
  144.   # The "children" of a minmod should be the next node, plus its children.
  145.   elsif ($node->{TYPE} eq 'MINMOD') {
  146.     my $affected = $node->{NEXT};
  147.     my ($start,undef) = $o->childNodesRange($affected);
  148.     my (undef, $stop) = $o->nodeRange($affected, 0);
  149.     push @ret, $start, $stop;
  150.   }
  151.   return wantarray ? @ret : \@ret;
  152. }
  153.  
  154. sub nodeId {
  155.   my $o = shift;
  156.   my $offset = shift;
  157.  
  158.   if ($offset < 0 or $offset >= length $o->{regex}) {
  159.     print STDERR "ActiveState::Rx::Info::nodeId($offset)\n";
  160.     print STDERR "  Error: Offset out of range.\n";
  161.     return;
  162.   }
  163.  
  164.   my $uregex = $o->{uregex};
  165.   my @sorted_ranges = @{$o->{ranges}};
  166.  
  167.   # now select the one we want:
  168.   for (my $i=0; $i<@sorted_ranges; $i++) {
  169.     my @q = @{$sorted_ranges[$i]};
  170.     my $start_of_range = $q[0];
  171.     my $end_of_range = $start_of_range + $q[1];
  172.     
  173.     if ($offset >= $start_of_range and $offset < $end_of_range) {
  174.       return $q[2]
  175.         if defined $uregex->{$q[2]};
  176.       # This is an interesting case -- it means that node disappeared
  177.       # at some point during optimization. The easiest way to see this
  178.       # is in this expression: (ab)*
  179.       #
  180.       # OFFSET   =>   NODE   =>   TYPE
  181.       # 0        =>   2      =>   OPTIMIZED
  182.       # 1        =>   4      =>   EXACT
  183.       # 2        =>   4      =>   EXACT
  184.       # 3        =>   node not found
  185.       # 4        =>   0      =>   CURLYM
  186.       #
  187.       # In this case, we can't highlight the node, find its parent,
  188.       # or anything like that, since we have no idea which node it 
  189.       # corresponded to in the original string.
  190.       
  191.       print STDERR "warning -- this node has been optimized away by " . 
  192.         "Perl's regex engine!\n";
  193.     }
  194.   }
  195. }
  196.  
  197. sub groupId {
  198.   my $o = shift;
  199.   my $id = shift;
  200.   my $node = $o->get_tnode($id);
  201.   return $node->{ARGS} if ($node->{TYPE} eq 'OPEN' or
  202.                            $node->{TYPE} eq 'CLOSE');
  203.   return 0;
  204. }
  205.  
  206. # matchId() has nothing to do with match(). It returns the node which
  207. # "matches" the node passed in. Currently, it only handles OPEN and
  208. # CLOSE nodes.
  209. sub matchId {
  210.   my $o = shift;
  211.   my $id = shift;
  212.   my $m = "";
  213.  
  214.   my $node = $o->{uregex}{$id};
  215.   if ($node->{TYPE} eq 'OPEN') {
  216.     $m = $o->{groups}{$node->{ARGS}}{CLOSE};
  217.   }
  218.   elsif ($node->{TYPE} eq 'CLOSE') {
  219.     $m = $o->{groups}{$node->{ARGS}}{OPEN};
  220.   }
  221.   return $m;
  222. }
  223.  
  224. sub findnode {
  225.   return find_tnode(@_)->{__this__};
  226. }
  227.  
  228. #=============================================================================
  229. # Subs below are for internal use only.
  230. #=============================================================================
  231.  
  232. sub DESTROY {
  233.   my $o = shift;
  234.  
  235. }
  236.  
  237. sub _sort_ranges {
  238.   my $o = shift;
  239.   
  240.   my @offsets = @{$o->{uregex}{OFFSETS}};
  241.   my @lengths = @{$o->{uregex}{LENGTHS}};
  242.   
  243.   my @sorted_ranges;
  244.   for (my $i=0; $i<@offsets; $i++) {
  245.     if (defined $offsets[$i] and defined $lengths[$i]) {
  246.       push @sorted_ranges, [$offsets[$i] - 1,  # offset
  247.                             $lengths[$i],      # length
  248.                             $i,                # MJD's id
  249.                            ];
  250.     }
  251.   }
  252.   
  253.   @sorted_ranges = sort { $a->[0] <=> $b->[0] } @sorted_ranges;
  254.   $o->{ranges} = \@sorted_ranges;
  255. }
  256.  
  257. sub _count_groups {
  258.   my $o = shift;
  259.   for my $key (keys %{$o->{uregex}}) {
  260.     next if substr($key,0,2) eq "__" or $key eq 'OFFSETS' or $key eq 'LENGTHS';
  261.     my $node = $o->{uregex}{$key};
  262.     next unless defined $node->{TYPE};
  263.     if ($node->{TYPE} eq 'OPEN' or
  264.         $node->{TYPE} eq 'CLOSE') {
  265.       $o->{groups}{$node->{ARGS}}{$node->{TYPE}} = $key;
  266.     }
  267.   }
  268. }
  269.  
  270. sub _match {
  271.   my $o = shift;
  272.   my $target = shift;
  273.   my @ret;
  274.   return unless $target =~ $o->{cregex};
  275.   for (my $i=0; $i<@+; $i++) {
  276.     if ($+[$i] == $-[$i]) { push @ret, undef, undef }
  277.     else {
  278.       push @ret, $-[$i], $+[$i]-1 
  279.         if $+[$i] >= 0 and $-[$i] >= 0;
  280.     }
  281.   }
  282.   return @ret;
  283. }
  284.  
  285. # We have to cheat a little to get the offset information
  286. sub _multimatch {
  287.   my $o = shift;
  288.   my $target = shift;
  289.  
  290.   # Capture the "raw offsets"
  291.   my $start = undef;
  292.   my $end = 0;
  293.   my @ret;
  294.   while (1) {
  295.     # Get one match (and break if it fails)
  296.     my (@pairs) = $o->_match($target);
  297.     last unless @pairs;
  298.  
  299.     # Remove the $& pair (the first pair)
  300.     my @trunc = splice @pairs, 0, 2;
  301.     for my $foo (@pairs) { $foo += $end if defined $foo; }
  302.  
  303.     # Update the span, set up the next target.
  304.     $start = $trunc[0] unless defined $start;
  305.     $end += $trunc[1] + 1;
  306.     my $ntarget = substr($target, $trunc[1] + 1);
  307.     last if $ntarget eq $target; # prevent infinite loop
  308.     $target = $ntarget;
  309.  
  310.     # Add the shifted pairs to the return array
  311.     push @ret, @pairs;
  312.   }
  313.  
  314.   # Last-minute cleanup
  315.   $end--;
  316.   splice @ret, 0, 0, $start, $end;
  317.   return @ret;
  318. }
  319.  
  320. sub get_tnode {
  321.   my $o = shift;
  322.   my $id = shift;
  323.   $o->{cached_tnodes}{$id} = $o->find_tnode($id)
  324.     unless defined $o->{cached_tnodes}{$id};
  325.   return $o->{cached_tnodes}{$id};
  326. }
  327.  
  328. sub find_tnode {
  329.   my $o = shift;
  330.   my $list = ref $_[0] eq 'ARRAY' ? shift : $o->{tregex};
  331.   my $id = shift if (@_ % 2);
  332.   my %criteria = @_;
  333.   $criteria{__this__} ||= $id if $id;
  334.  
  335.   for my $node (@$list) {
  336.     my $matched = 1;
  337.     for my $key (keys %criteria) {
  338.       $matched &= (defined $node->{$key} and $node->{$key} eq $criteria{$key});
  339.     }
  340.     return $node if $matched;
  341.     if ($node->{CHILD}) {
  342.       my $n = $o->find_tnode($node->{CHILD}, %criteria);
  343.       return $n if $n;
  344.     }
  345.   }
  346.   return undef;
  347. }
  348.  
  349. sub tip_star {
  350.   my ($o, $n, $i, $h, $r, $m) = @_;
  351.   my ($start, $stop) = $o->childNodesRange($i);
  352.   my $child = substr($h->{REGEX},$start,$stop-$start+1);
  353.  
  354.   my $c = $o->get_tnode($n->{CHILD});
  355.   return "Match '$child' 0 or more times" if $c->{TYPE} eq 'EXACT';
  356.   return "Match <$child> 0 or more times";
  357. }
  358.  
  359. sub tip_plus {
  360.   my ($o, $n, $i, $h, $r, $m) = @_;
  361.   my ($start, $stop) = $o->childNodesRange($i);
  362.   my $child = substr($h->{REGEX},$start,$stop-$start+1);
  363.   my $c = $o->get_tnode($n->{CHILD});
  364.   return "Match '$child' 1 or more times" if $c->{TYPE} eq 'EXACT';
  365.   return "Match <$child> 1 or more times";
  366. }
  367.  
  368. sub tip_curly {
  369.   my ($o, $n, $i, $h, $r, $m) = @_;
  370.   my ($min, $max) = @{$n->{ARGS}};
  371.   my ($start, $stop) = $o->childNodesRange($i);
  372.   my $child = substr($h->{REGEX},$start,$stop-$start+1);
  373.   my $c = $o->get_tnode($n->{CHILD});
  374.   return "Match '$child' $min to $max times" if $c->{TYPE} eq 'EXACT';
  375.   return "Match <$child> $min to $max times";
  376. }
  377.  
  378. sub tip_curlyx {
  379.   my ($o, $n, $i, $h, $r, $m) = @_;
  380.   my ($min, $max) = @{$n->{ARGS}};
  381.   my ($start,$stop) = $o->childNodesRange($i);
  382.   my $child = substr($h->{REGEX},$start,$stop-$start+1);
  383.   my $quant;
  384.   if ($max == 32767 or
  385.       $max == 2147483647) {
  386.     $quant = "$min or more";
  387.   }
  388.   else {
  389.     $quant = "$min to $max";
  390.   }
  391.   return "Match <$child> $quant times";
  392. }
  393.  
  394. sub tip_anyof {
  395.   my ($o, $n, $i, $h, $r, $m) = @_;
  396.   my ($start,$stop) = $o->nodeRange($i,0);
  397.   my $klass = substr($h->{REGEX},$start,$stop-$start+1);
  398.   my $not = "";
  399.   if (substr($klass, 1, 1) eq '^') {
  400.     substr($klass, 1, 1, "");
  401.     $not = " not";
  402.   }
  403.   return "Match any character$not in $klass";
  404. }
  405.  
  406. sub tip_minmod {
  407.   my ($o, $n, $i, $h, $r, $m) = @_;
  408.   my $affected = $n->{NEXT};
  409.   my ($start,undef) = $o->childNodesRange($affected);
  410.   my (undef,$stop) = $o->nodeRange($affected,0);
  411.   my $str = substr($h->{REGEX}, $start, $stop-$start+1);
  412.   return "Match <$str> non-greedily";
  413. }
  414.  
  415. BEGIN {
  416.   %tips =
  417.     (
  418.      END => q{"End of regular expression"},
  419.      SUCCEED => q{"Return from a subexpression"},
  420.      BOL => q{"Match the beginning of the string"},
  421.      MBOL => q{"Match the beginning of any line"},
  422.      SBOL => q{"Match the beginning of the string"},
  423.      EOS => q{"Match the end of the string"},
  424.      EOL => q{"Match the end of the string"},
  425.      MEOL => q{"Match the end of any line"},
  426.      SEOL => q{"Match the end of the line"},
  427.      BOUND => q{"Match any word boundary"},
  428.      BOUNDL => q{"Match any word boundary"},
  429.      NBOUND => q{"Match any word non-boundary"},
  430.      NBOUNDL => q{"Match any word non-boundary"},
  431.      GPOS => q{"Matches where last m//g left off"},
  432.      
  433.      # [Special] alternatives
  434.      REG_ANY => q{"Match any one character (except newline)"},
  435.      ANY => q{"Match any one character (except newline)"},
  436.      SANY => q{"Match any one character (including newline)"},
  437.      ANYOF => q{tip_anyof(@_)},
  438.      ALNUM => q{"Match any alphanumeric character"},
  439.      ALNUML => q{"Match any alphanumeric char in locale"},
  440.      NALNUM => q{"Match any non-alphanumeric character"},
  441.      NALNUML => q{"Match any non-alphanumeric char in locale"},
  442.      SPACE => q{"Match any whitespace character"},
  443.      SPACEL => q{"Match any whitespace char in locale"},
  444.      NSPACE => q{"Match any non-whitespace character"},
  445.      NSPACEL => q{"Match any non-whitespace char in locale"},
  446.      DIGIT => q{"Match any numeric character"},
  447.      NDIGIT => q{"Match any non-numeric character"},
  448.      
  449.      # BRANCH    The set of branches constituting a single choice are hooked
  450.      #           together with their "next" pointers, since precedence prevents
  451.      #           anything being concatenated to any individual branch.  The
  452.      #           "next" pointer of the last BRANCH in a choice points to the
  453.      #           thing following the whole choice.  This is also where the
  454.      #           final "next" pointer of each individual branch points; each
  455.      #           branch starts with the operand node of a BRANCH node.
  456.      #
  457.      BRANCH => q{"Match this alternative, or the next"},
  458.      
  459.      # BACK      Normal "next" pointers all implicitly point forward; BACK
  460.      #           exists to make loop structures possible.
  461.      # not used
  462.      BACK => q{"Match \"\", \"next\" ptr points backward"},
  463.      
  464.      # Literals
  465.      EXACT => q{"Match '${\\$n->{STRING}}'"},
  466.      EXACTF => q{"Match '${\\$n->{STRING}}'"},
  467.      EXACTFL => q{"Match '${\\$n->{STRING}}'"},
  468.      
  469.      # Do nothing
  470.      NOTHING => q{"Match empty string"},
  471.      # A variant of above which delimits a group, thus stops optimizations
  472.      TAIL => q{"Match empty string"},
  473.      
  474.      # STAR,PLUS '?', and complex '*' and '+', are implemented as circular
  475.      #           BRANCH structures using BACK.  Simple cases (one character
  476.      #           per match) are implemented with STAR and PLUS for speed
  477.      #           and to minimize recursive plunges.
  478.      #
  479.      STAR => q{tip_star(@_)},
  480.      PLUS => q{tip_plus(@_)},
  481.      CURLY => q{tip_curly(@_)},
  482.      CURLYN => q{"Match next-after-this simple thing"},
  483.      CURLYM => q{"Match this medium-complex thing {n,m} times"},
  484.      CURLYX => q{tip_curlyx(@_)},
  485.      
  486.      # This terminator creates a loop structure for CURLYX
  487.      WHILEM => q{"Do curly processing and see if rest matches"},
  488.      
  489.      # OPEN,CLOSE,GROUPP ...are numbered at compile time.
  490.      OPEN => q{"Capture group \$${\\$n->{ARGS}}"},
  491.      CLOSE => q{"Capture group \$${\\$n->{ARGS}}"},
  492.      
  493.      REF => q{"Match some already matched string"},
  494.      REFF => q{"Match some already matched string"},
  495.      REFFL => q{"Match some already matched string"},
  496.      
  497.      # grouping assertions
  498.      IFMATCH => q{"Succeeds if the following matches"},
  499.      UNLESSM => q{"Fails if the following matches"},
  500.      SUSPEND => q{"Independent sub-RE"},
  501.      IFTHEN => q{"Switch, should be preceeded by switcher"},
  502.      GROUPP => q{"Whether the group matched"},
  503.      
  504.      # Support for long RE
  505.      LONGJMP => q{"Jump far away"},
  506.      BRANCHJ => q{"BRANCH with long offset"},
  507.      
  508.      # The heavy worker
  509.      EVAL => q{"Execute some Perl code"},
  510.      
  511.      # Modifiers
  512.      MINMOD => q{tip_minmod(@_)},
  513.      LOGICAL => q{"${\\$h->{$n->{NEXT}}->{TYPE}} should set the flag only"},
  514.      
  515.      # This is not used yet
  516.      RENUM => q{"Group with independently numbered parens"},
  517.      
  518.      # This is not really a node, but an optimized away piece of a "long" node.
  519.      # To simplify debugging output, we mark it as if it were a node
  520.      OPTIMIZED => q{"Placeholder for dump"},
  521.     );
  522. }
  523.  
  524. __END__
  525.  
  526. =head1 NAME
  527.  
  528. ActiveState::Rx::Info -- An object-oriented interface to the Regular Expression debugger.
  529.  
  530. =head1 SYNOPSIS
  531.  
  532.   use ActiveState::Rx::Info;
  533.  
  534.   my $obj = ActiveState::Rx::Info->new('(.*)(\d+)');
  535.   print "Matched!" if ($obj->match('testing 123'));
  536.   print "The number of groups in this regex is: $obj->groupCount\n";
  537.   my $nid = $obj->findnode(TYPE => 'OPEN', ARGS => 1);
  538.   print "The start of group 1 is at offset: ", 
  539.     $obj->nodeRange($nid), "\n";
  540.  
  541. This complete program prints out:
  542.  
  543.   Matched!
  544.   The number of groups in this regex is: 2
  545.   The start of group 1 is at offset: 0
  546.  
  547. =head1 DESCRIPTION
  548.  
  549. ActiveState::Rx::Info is designed to provide a higher level
  550. abstraction of the regular expression debugger than does
  551. ActiveState::Rx. The modified compiler and executor are kept in
  552. ActiveState::Rx, but ActiveState::Rx::Info makes it easier to use.
  553.  
  554. =head1 API
  555.  
  556. The following sections document the methods available from
  557. ActiveState::Rx::Info.
  558.  
  559. =head2 new(regex[, modifiers])
  560.  
  561. Creates a ActiveState::Rx::Info object. 'regex' is the regular
  562. expression to generate information about, and 'modifiers' is an
  563. optional parameter containing perl modifiers g, i, s, m, o, and x.
  564.  
  565. =head2 regex()
  566.  
  567. Returns the string form of the regular expression stored in the object.
  568.  
  569. =head2 modifiers()
  570.  
  571. Returns the string form of the modifiers stored in the object.
  572.  
  573. =head2 groupCount()
  574.  
  575. Returns the number of groups found in the regex. For example,
  576.  
  577.   use ActiveState::Rx::Info;
  578.   my $gc = ActiveState::Rx::Info->new('(abc*)')->groupCount;
  579.  
  580. In this example, C<$gc> will be set to 1. 
  581.  
  582. =head2 nodeId(offset)
  583.  
  584. Returns the 'node id' of the node found at the given offset into the
  585. regular expression string. Most API functions in ActiveState::Rx::Info
  586. operate on a node id, since that is how regular expressions are
  587. manipulated internally.
  588.  
  589. =head2 maxLevel(nodeId)
  590.  
  591. Returns the maximum 'level' of the node. Level is an abstract concept
  592. -- so abstract it hasn't even been nailed down. Yet. This function
  593. currently doesn't do anything except return 0.
  594.  
  595. =head2 match(target)
  596.  
  597. Attempts to apply the regular expression to the target string. Returns
  598. a list of offsets in the target string, designed to aid highlighting
  599. the parts of the string which corresponded to groups in the regular
  600. expression.
  601.  
  602. Here is an example:
  603.  
  604.   use ActiveState::Rx::Info;
  605.   my @m = ActiveState::Rx::Info->new('(.*)(\d+)')->match('testing123');
  606.  
  607. In this example, C<@m> is set to (0, 9, 0, 8, 9, 9). These numbers
  608. represent three pairs of numbers: (0, 9), (0, 8), and (9, 9). I<These>
  609. pairs represent substrings of the target string corresponding to
  610. matches. The first pair is always the substring C<$&>, or the extents
  611. of the match. The remaining pairs all refer to C<$1>, C<$2>, and so
  612. on. If global matching is turned on, then there will be I<one> C<$&>
  613. at the beginning, and one pair for each iteration of the match.
  614.  
  615. If no string was matched by the particular pair, they are both undef.
  616.  
  617. =head2 nodeTip(nodeId)
  618.  
  619. Returns a node tip corresponding to the given regular expression
  620. node. For example:
  621.  
  622.   use ActiveState::Rx::Info; 
  623.   my $o = ActiveState::Rx::Info->new('abc*'); 
  624.   print $o->nodeTip($o->nodeId(0));
  625.  
  626. will print I<Match 'ab'>. 
  627.  
  628. =head2 nodeRange(nodeId)
  629.  
  630. Returns the range of the node in the regular expression string. For example:
  631.  
  632.   use ActiveState::Rx::Info;
  633.   my $o = ActiveState::Rx::Info->new('abc*');
  634.   print join ', ', $o->nodeRange($o->nodeId(0));
  635.  
  636. will print I<0, 1>. 
  637.  
  638. =head2 childNodesRange(nodeId)
  639.  
  640. Returns the range of any children of the given node. Some nodes do not have
  641. children; they will return an empty list.
  642.  
  643. =head2 groupId(nodeId)
  644.  
  645. Returns the group number that nodeId refers to. Only supported if nodeId 
  646. is either an OPEN or CLOSE node. 
  647.  
  648. =head2 matchId(nodeId)
  649.  
  650. Returns the nodeId of a node which "matches" the given node. Currently only
  651. implemented if nodeId refers to a OPEN or CLOSE node. If nodeId returns to 
  652. an OPEN node, it returns the node id of the corresponding CLOSE, and vice 
  653. versa.
  654.  
  655. =head2 findnode(criteria)
  656.  
  657. Searches the nodes in the regular expression for a matching node. Returns the
  658. node id of the matching node structure. For example:
  659.  
  660.   use ActiveState::Rx::Info;
  661.   my $o = ActiveState::Rx::Info->new('ab(c*)');
  662.   my $nid = $o->findnode(TYPE => OPEN, ARGS => 1);
  663.  
  664. This example set C<$nid> to the node id referring to the first OPEN node
  665. in the regular expression. 
  666.  
  667. =head1 AUTHOR
  668.  
  669. Neil Watkiss <neilw@ActiveState.com>
  670. ActiveState Corporation
  671.  
  672. =head1 COPYRIGHT
  673.  
  674. Copyright (c) 2001, ActiveState Corp. All rights reserved.
  675. ActiveState is a devision of Sophos.
  676.  
  677. =cut
  678.