[Templates-cvs] cvs commit: TT3/lib/Template/TT3 Scanner.pm

cvs@template-toolkit.org cvs@template-toolkit.org
Mon, 15 Dec 2003 15:31:12 +0000


cvs         03/12/15 15:31:12

  Modified:    lib/Template/TT3 Scanner.pm
  Log:
  * moved scanning for end tag and line counting out of tag into scanner
    scan() method
  
  Revision  Changes    Path
  1.4       +107 -19   TT3/lib/Template/TT3/Scanner.pm
  
  Index: Scanner.pm
  ===================================================================
  RCS file: /template-toolkit/TT3/lib/Template/TT3/Scanner.pm,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Scanner.pm	2003/12/11 15:11:37	1.3
  +++ Scanner.pm	2003/12/15 15:31:12	1.4
  @@ -18,7 +18,7 @@
   #   modify it under the same terms as Perl itself.
   #
   # REVISION
  -#   $Id: Scanner.pm,v 1.3 2003/12/11 15:11:37 abw Exp $
  +#   $Id: Scanner.pm,v 1.4 2003/12/15 15:31:12 abw Exp $
   #
   #========================================================================
   
  @@ -30,7 +30,7 @@
   use vars qw( $VERSION $DEBUG $ERROR $WARNING $TAGS );
   use base qw( Template::TT3::Base );
   
  -$VERSION = sprintf("%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/);
  +$VERSION = sprintf("%d.%02d", q$Revision: 1.4 $ =~ /(\d+)\.(\d+)/);
   $DEBUG   = 0 unless defined $DEBUG;
   $ERROR   = '';
   $TAGS    = [ ];
  @@ -105,7 +105,7 @@
       # object so instead we keep a list of them for matching later.
       
       foreach my $tag (@$tags) {
  -        my $start = $tag->start();
  +        my $start = $tag->{ start };
           if (ref $start eq 'Regexp') {
               push(@$regexen, $start);
               push(@$regtags, $tag);
  @@ -164,10 +164,13 @@
   
       $self->debug("scan()\n") if $DEBUG;
       $self->{ reset } = 0;
  +    $self->{ line  } = 1;
  +    $self->{ size  } = 0;
   
       SCAN_FOR_TAGS: {
           # fetch the tagset information prepared by the tags() method
           my ($tagmap, $regex, $regexen) = @$self{ qw( tagmap regex regexen  ) };
  +
           if ($regex) {
               $self->debug("scanning with regex: $regex\n") if $DEBUG;
           }
  @@ -178,15 +181,19 @@
   
           # scan source text to identify text and tags
           while ($$textref =~ /$regex/cg) {
  -            my ($pretext, $dirtok) = ($1, $2);
  +            my ($pretext, $start) = ($1, $2);
  +            my $end;
   
  -            # notify template document of any text preceeding a tag
  -            $document->text(\$pretext) 
  -                || return $self->error($document->error())
  -                    if defined $pretext && length $pretext;
  +            # is there any text preceding the tag start?
  +            if (defined $pretext && length $pretext) {
  +                # count newlines and notify document
  +                $self->{ line } += ($pretext =~ tr/\n//);
  +                $document->text(\$pretext) 
  +                    || return $self->scan_error($document->error());
  +            }
   
               # look for the tag object corresponding to this start token
  -            my $tag = $tagmap->{ $dirtok };
  +            my $tag = $tagmap->{ $start };
   
               # if there isn't an entry in the tag lookup table then we 
               # look through each regex to find out which one matches the
  @@ -194,23 +201,73 @@
               unless (defined $tag) {
                   my $regexen = $self->{ regexen };
                   for my $n (0..$#$regexen) {
  -                    if ($dirtok =~ $regexen->[$n]) {
  -                        $self->debug("matched $dirtok against $regexen->[$n]\n") 
  +                    if ($start =~ $regexen->[$n]) {
  +                        $self->debug("matched $start against $regexen->[$n]\n") 
                               if $DEBUG;
                           $tag = $self->{ regtags }->[$n]
  -                            || return $self->error("no tag for regex $regexen->[$n]");
  +                            || return $self->scan_error("no tag for regex $regexen->[$n]");
                           # cached tag found for the start token in tagmap
  -                        $tagmap->{ $dirtok } = $tag;
  +                        $tagmap->{ $start } = $tag;
                           last;
                       }
                   }
  -                return $self->error("no tag defined for '$dirtok'")
  +                return $self->scan_error("no tag defined for '$start'")
                       unless defined $tag;
               }
   
  -            # call tag object to scan the tag content
  -            $tag->scan($dirtok, $textref, $document)
  -                || return $self->error($tag->error());
  +            # scan the tag content
  +            if (defined ($end = $tag->{ end }) && length($end)) {
  +                # this is a closed tag that has pre-defined start and end tokens.
  +                # we scan up to the end tag, figure out how many lines the directive
  +                # covers and then call the parse() method to parse the contents
  +
  +                $self->debug("scanning closed tag from $start to $end\n") if $DEBUG;
  +
  +                # generate regex to match end tag
  +                my $regex = $tag->{ end_regex } ||= do {
  +                    $end = ref $end eq 'Regexp' ? $end : quotemeta($end);
  +                    qr/ \G (.*?) ($end) /sx;
  +                };
  +                
  +                # scan for closing tag and report error if not found
  +                return $self->scan_error("no closing tag to match $start")
  +                    unless $$textref =~ /$regex/gc;
  +                my ($content, $end) = ($1, $2);
  +
  +                # count lines in start tag, content and end tag
  +                $self->{ size } = ( $start   =~ tr/\n// ) 
  +                                + ( $content =~ tr/\n// ) 
  +                                + ( $end     =~ tr/\n// );
  +
  +                # call tag scan() method to handle tag content
  +                $tag->scan(\$content, $document, $start, $end)
  +                    || return $self->scan_error($tag->error());
  +
  +                # update document position 
  +                $self->{ line } += $self->{ size };
  +                $self->{ size }  = 0;
  +            }
  +            else {
  +                # an open tag that has a start but no pre-defined end token.
  +                # we save the current regex position, call the parse method to 
  +                # gobble up as much of the text as it likes, and then examine 
  +                # the regex position again, and count the newlines in the
  +                # intervening text to update the document line position
  +
  +                $self->debug("scanning open tag from $start\n") if $DEBUG;
  +
  +                # save starting regex position
  +                my $start_pos = pos($$textref) || 0;
  +
  +                # call tag scan() method to scan forwards
  +                $tag->scan($textref, $document, $start)
  +                    || return $self->scan_error($tag->error());
  +    
  +                # count any newlines consumed between start and end positions
  +                my $end_pos = pos $$textref || 0;
  +                my $substr  = substr($$textref, $start_pos, $end_pos - $start_pos);
  +                $self->{ line } += ($substr =~ tr/\n//);
  +            }
   
               # check to see if tags have changed
               if ($self->{ reset }) {
  @@ -220,10 +277,11 @@
           }
       }
   
  +    # scan for any trailing text
       if ($$textref =~ / \G (.+) /sx) {
           my $text = $1;
           $document->text(\$text) 
  -            || return $self->error($document->error());
  +            || return $self->scan_error($document->error());
       }
   
       return 1;
  @@ -231,6 +289,35 @@
   
   
   
  +sub line {
  +    my $self = shift;
  +    return @_ ? ($self->{ line } = shift) : $self->{ line };
  +}
  +
  +sub size {
  +    my $self = shift;
  +    return @_ ? ($self->{ size } = shift) : $self->{ size };
  +}
  +
  +sub position {
  +    my $self = shift;
  +
  +    if (@_) {
  +        $self->{ line } += shift;
  +        $self->{ size }  = @_ ? shift : 0;
  +    }
  +    if ($self->{ size }) {
  +        my $end = $self->{ line } + $self->{ size };
  +        return "$self->{ line }-$end";
  +    }
  +    else {
  +        return $self->{ line };
  +    }
  +}
  +
  +
  +
  +
   1;
   __END__
   
  @@ -260,7 +347,7 @@
   
   =head1 VERSION
   
  -$Revision: 1.3 $
  +$Revision: 1.4 $
   
   =head1 COPYRIGHT
   
  @@ -279,3 +366,4 @@
   # End:
   #
   # vim: expandtab shiftwidth=4:
  +