home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / Lexer.pm < prev    next >
Encoding:
Perl POD Document  |  2003-11-12  |  17.1 KB  |  679 lines

  1. # Copyright (c) 1998-2003 by Jonathan Swartz. All rights reserved.
  2. # This program is free software; you can redistribute it and/or modify it
  3. # under the same terms as Perl itself.
  4.  
  5. package HTML::Mason::Lexer;
  6.  
  7. use strict;
  8.  
  9. use HTML::Mason::Exceptions( abbr => [qw(param_error syntax_error error)] );
  10.  
  11. use HTML::Mason::Tools qw( taint_is_on );
  12.  
  13. use Params::Validate qw(:all);
  14. Params::Validate::validation_options( on_fail => sub { param_error join '', @_ } );
  15.  
  16. use Class::Container;
  17. use base qw(Class::Container);
  18.  
  19. # This is a block name and what method should be called to lex its
  20. # contents if it is encountered.  'def' & 'method' blocks are special
  21. # cases we actually call ->start again to recursively parse the
  22. # contents of a subcomponent/method.  Theoretically, adding a block is
  23. # as simple as adding an entry to this hash, and possibly a new
  24. # contents lexing methods.
  25. my %blocks = ( args    => 'variable_list_block',
  26.            attr    => 'key_val_block',
  27.            flags   => 'key_val_block',
  28.            cleanup => 'raw_block',
  29.            doc     => 'doc_block',
  30.            filter  => 'raw_block',
  31.            init    => 'raw_block',
  32.            once    => 'raw_block',
  33.            perl    => 'raw_block',
  34.            shared  => 'raw_block',
  35.            text    => 'text_block',
  36.          );
  37.  
  38. sub block_names
  39. {
  40.     return keys %blocks;
  41. }
  42.  
  43. sub block_body_method
  44. {
  45.     return $blocks{ $_[1] };
  46. }
  47.  
  48. {
  49.     my $blocks_re;
  50.  
  51.     my $re = join '|', __PACKAGE__->block_names;
  52.     $blocks_re = qr/$re/i;
  53.  
  54.     sub blocks_regex
  55.     {
  56.     return $blocks_re;
  57.     }
  58. }
  59.  
  60. sub lex
  61. {
  62.     my $self = shift;
  63.     my %p = validate(@_,
  64.              {comp_source => SCALAR|SCALARREF,
  65.               name => SCALAR,
  66.               compiler => {isa => 'HTML::Mason::Compiler'}}
  67.             );
  68.  
  69.     # Note - we could improve memory usage here if we didn't make a
  70.     # copy of the scalarref, but that will take some more work to get
  71.     # it working
  72.     $p{comp_source} = ${$p{comp_source}} if ref $p{comp_source};
  73.  
  74.     # Holds information about the current lex.  Make it local() so
  75.     # we're fully re-entrant.
  76.     local $self->{current} = \%p;
  77.     my $current = $self->{current}; # For convenience
  78.  
  79.     # Clean up Mac and DOS line endings
  80.     $current->{comp_source} =~ s/\r\n?/\n/g;
  81.  
  82.     # Initialize lexer state
  83.     $current->{lines} = 1;
  84.     $current->{in_def} = $current->{in_method} = 0;
  85.  
  86.     # This will be overridden if entering a def or method section.
  87.     $current->{ending} = qr/\G\z/;
  88.  
  89.     # We need to untaint the component or else the regexes will fail
  90.     # to a Perl bug.  The delete is important because we need to
  91.     # create an entirely new scalar, not just modify the existing one.
  92.     ($current->{comp_source}) = (delete $current->{comp_source}) =~ /(.*)/s
  93.         if taint_is_on;
  94.  
  95.     eval
  96.     {
  97.     $current->{compiler}->start_component;
  98.     $self->start;
  99.     };
  100.     # Call this out here because it may be needed to break circular
  101.     # refs inside the compiler
  102.     $current->{compiler}->end_component;
  103.  
  104.     rethrow_exception $@;
  105. }
  106.  
  107. sub object_id
  108. {
  109.     my $self = shift;
  110.  
  111.     my @vals;
  112.     foreach my $k ( sort keys %{ $self->validation_spec } )
  113.     {
  114.     next if $k eq 'container';
  115.  
  116.     push @vals, $k;
  117.     push @vals, ( UNIVERSAL::isa( $self->{$k}, 'HASH' )  ? map { $_ => $self->{$k}{$_} } sort keys %{ $self->{$k} } :
  118.               UNIVERSAL::isa( $self->{$k}, 'ARRAY' ) ? sort @{ $self->{$k} } :
  119.               $self->{$k} );
  120.     }
  121.  
  122.     local $^W; # ignore undef warnings
  123.     # unpack('%32C*', $x) computes the 32-bit checksum of $x
  124.     return unpack('%32C*', join "\0", class => ref($self), @vals);
  125. }
  126.  
  127. sub start
  128. {
  129.     my $self = shift;
  130.  
  131.     my $end;
  132.     while (1)
  133.     {
  134.     last if $end = $self->match_end;
  135.  
  136.     $self->match_block && next;
  137.  
  138.     $self->match_named_block && next;
  139.  
  140.     $self->match_substitute && next;
  141.  
  142.     $self->match_comp_call && next;
  143.  
  144.     $self->match_perl_line && next;
  145.  
  146.     $self->match_comp_content_call && next;
  147.  
  148.     $self->match_comp_content_call_end && next;
  149.  
  150.     $self->match_text && next;
  151.  
  152.     if ( ( $self->{current}{in_def} || $self->{current}{in_method} ) &&
  153.          $self->{current}{comp_source} =~ /\G\z/ )
  154.     {
  155.         my $type = $self->{current}{in_def} ? 'def' : 'method';
  156.         $self->throw_syntax_error("Missing closing </%$type> tag");
  157.     }
  158.  
  159.     last if $self->{current}{comp_source} =~ /\G\z/;
  160.  
  161.     # We should never get here - if we do, we're in an infinite loop.
  162.     $self->throw_syntax_error("Infinite parsing loop encountered - Lexer bug?");
  163.     }
  164.  
  165.     if ( $self->{current}{in_def} || $self->{current}{in_method} )
  166.     {
  167.     my $type = $self->{current}{in_def} ? 'def' : 'method';
  168.     unless ( $end =~ m,</%\Q$type\E>\n?,i )
  169.     {
  170.         my $block_name = $self->{current}{"in_$type"};
  171.         $self->throw_syntax_error("No </%$type> tag for <%$type $block_name> block");
  172.     }
  173.     }
  174. }
  175.  
  176. sub match_block
  177. {
  178.     my $self = shift;
  179.  
  180.     my $blocks_re = $self->blocks_regex;
  181.  
  182.     if ( $self->{current}{comp_source} =~ /\G<%($blocks_re)>/igcs )
  183.     {
  184.     my $type = lc $1;
  185.     $self->{current}{compiler}->start_block( block_type => $type );
  186.  
  187.     my $method = $self->block_body_method($type);
  188.     $self->$method( {block_type => $type} );
  189.  
  190.     return 1;
  191.     }
  192. }
  193.  
  194. sub generic_block
  195. {
  196.     my ($self, $method, $p) = @_;
  197.  
  198.     $p->{allow_text} = 1;
  199.     my ($block, $nl) = $self->match_block_end( $p );
  200.  
  201.     $self->{current}{compiler}->$method( block_type => $p->{block_type},
  202.                      block => $block );
  203.  
  204.     $self->{current}{lines} += $block =~ tr/\n//;
  205.     $self->{current}{lines}++ if $nl;
  206.  
  207.     $self->{current}{compiler}->end_block( block_type => $p->{block_type} );
  208. }
  209.  
  210. sub text_block
  211. {
  212.     my $self = shift;
  213.     $self->generic_block('text_block', @_);
  214. }
  215.  
  216. sub raw_block
  217. {
  218.     my $self = shift;
  219.     $self->generic_block('raw_block', @_);
  220. }
  221.  
  222. sub doc_block
  223. {
  224.     my $self = shift;
  225.     $self->generic_block('doc_block', @_);
  226. }
  227.  
  228. sub variable_list_block
  229. {
  230.     my ($self, $p) = @_;
  231.  
  232.     my $ending = qr/ \n | <\/%\Q$p->{block_type}\E> /ix;
  233.     while ( $self->{current}{comp_source} =~ m,
  234.                        \G               # last pos matched
  235.                        (?:
  236.                         [ \t]*
  237.                         ( [\$\@\%] )    # variable type
  238.                         ( [^\W\d]\w* )  # only allows valid Perl variable names
  239.                         [ \t]*
  240.                         # if we have a default arg we'll suck up
  241.                         # any comment it has as part of the default
  242.                         # otherwise explcitly search for a comment
  243.                         (?:
  244.                          (?:              # this entire entire piece is optional
  245.                            =>
  246.                           ( [^\n]+? )     # default value
  247.                          )
  248.                          |
  249.                          (?:              # an optional comment
  250.                           [ \t]*
  251.                           \#
  252.                           [^\n]*
  253.                          )
  254.                         )?
  255.                         (?= $ending )
  256.                         |
  257.                         [ \t]*          # a comment line
  258.                         \#
  259.                         [^\n]*
  260.                         (?= $ending )
  261.                         |
  262.                         [ \t]*          # just space
  263.                        )
  264.                        (\n |          # newline or
  265.                           (?= <\/%\Q$p->{block_type}\E> ) )   # end of block (don't consume it)
  266.                       ,ixgc
  267.       )
  268.     {
  269.     if ( defined $1 && defined $2 && length $1 && length $2 )
  270.     {
  271.         $self->{current}{compiler}->variable_declaration( block_type => $p->{block_type},
  272.                                   type => $1,
  273.                                   name => $2,
  274.                                   default => $3,
  275.                                 );
  276.     }
  277.  
  278.     $self->{current}{lines}++ if $4;
  279.     }
  280.  
  281.     $p->{allow_text} = 0;
  282.     my $nl = $self->match_block_end( $p );
  283.     $self->{current}{lines}++ if $nl;
  284.  
  285.     $self->{current}{compiler}->end_block( block_type => $p->{block_type} );
  286. }
  287.  
  288. sub key_val_block
  289. {
  290.     my ($self, $p) = @_;
  291.  
  292.     my $ending = qr, (?: \n |           # newline or
  293.                          (?= </%\Q$p->{block_type}\E> ) )   # end of block (don't consume it)
  294.                    ,ix;
  295.  
  296.     while ( $self->{current}{comp_source} =~ /
  297.                       \G
  298.                       [ \t]*
  299.                       ([\w_]+)          # identifier
  300.                       [ \t]*=>[ \t]*    # separator
  301.                       (\S[^\n]*?)       # value ( must start with a non-space char)
  302.                       $ending
  303.                       |
  304.                       \G\n              # a plain empty line
  305.                       |
  306.                       \G
  307.                       [ \t]*            # an optional comment
  308.                       \#
  309.                       [^\n]*
  310.                       $ending
  311.                       |
  312.                       \G[ \t]+?
  313.                       $ending
  314.                      /xgc )
  315.     {
  316.     if ( defined $1 && defined $2 && length $1 && length $2 )
  317.     {
  318.         $self->{current}{compiler}->key_value_pair( block_type => $p->{block_type},
  319.                             key => $1,
  320.                             value => $2
  321.                               );
  322.     }
  323.  
  324.     $self->{current}{lines}++;
  325.     }
  326.  
  327.     $p->{allow_text} = 0;
  328.     my $nl = $self->match_block_end( $p );
  329.     $self->{current}{lines}++ if $nl;
  330.  
  331.     $self->{current}{compiler}->end_block( block_type => $p->{block_type} );
  332. }
  333.  
  334. sub match_block_end
  335. {
  336.     my ($self, $p) = @_;
  337.  
  338.     my $re = $p->{allow_text} ? qr,\G(.*?)</%\Q$p->{block_type}\E>(\n?),is
  339.                               : qr,\G\s*</%\Q$p->{block_type}\E>(\n?),is;
  340.     if ( $self->{current}{comp_source} =~ /$re/gc )
  341.     {
  342.     return $p->{allow_text} ? ($1, $2) : $2;
  343.     }
  344.     else
  345.     {
  346.     $self->throw_syntax_error("Invalid <%$p->{block_type}> section line");
  347.     }
  348. }
  349.  
  350. sub match_named_block
  351. {
  352.     my ($self, $p) = @_;
  353.  
  354.     if ( $self->{current}{comp_source} =~ /\G<%(def|method)(?:\s+([^\n]+?))?\s*>/igcs )
  355.     {
  356.     my ($type, $name) = (lc $1, $2);
  357.  
  358.     $self->throw_syntax_error("$type block without a name")
  359.         unless defined $name && length $name;
  360.  
  361.     $self->{current}{compiler}->start_named_block( block_type => $type,
  362.                                name => $name );
  363.  
  364.     # This will cause ->start to return once it hits the
  365.     # appropriate ending tag.
  366.     local $self->{current}{ending} = qr,\G</%\Q$type\E>\n?,i;
  367.  
  368.     local $self->{current}{"in_$type"} = $name;
  369.  
  370.     $self->start();
  371.  
  372.     $self->{current}{compiler}->end_named_block( block_type => $type );
  373.  
  374.     return 1;
  375.     }
  376. }
  377.  
  378. # starts with an alpha character or underscore, followed by any word
  379. # character
  380. my $flag;
  381. if ( $] >= 5.006 )
  382. {
  383.     # Unicode-friendly
  384.  
  385.     # Use eval because 5.00503 complains even if it doesn't execute
  386.     # it.
  387.     eval '$flag = qr/[[:alpha:]_]\w*/;';
  388. }
  389. else
  390. {
  391.     # Like [a-zA-Z_] but respects locales
  392.     $flag = qr/[^\W\d]\w*/x;
  393. }
  394.  
  395. sub escape_flag_regex { $flag }
  396.  
  397. sub match_substitute
  398. {
  399.     # This routine relies on there *not* to be an opening <%foo> tag
  400.     # present, so match_block() must happen first.
  401.     
  402.     my $self = shift;
  403.  
  404.     return 0 unless $self->{current}{comp_source} =~ /\G<%/gcs;
  405.  
  406.     if ( $self->{current}{comp_source} =~
  407.      m{
  408.        \G
  409.        (.+?)                # Substitution body ($1)
  410.        (
  411.         \s*
  412.         (?<!\|)             # Not preceded by a '|'
  413.         \|                  # A '|'
  414.         \s*
  415.         (                   # (Start $3)
  416.          $flag              # A flag
  417.          (?:\s*,\s*$flag)*  # More flags, with comma separators
  418.         )
  419.         \s*
  420.        )?
  421.        %>                   # Closing tag
  422.       }xcigs )
  423.     {
  424.     $self->{current}{lines} += tr/\n// foreach grep defined, ($1, $2);
  425.  
  426.     $self->{current}{compiler}->substitution( substitution => $1,
  427.                           escape => $3 );
  428.     return 1;
  429.     }
  430.     else
  431.     {
  432.     $self->throw_syntax_error("'<%' without matching '%>'");
  433.     }
  434. }
  435.  
  436. sub match_comp_call
  437. {
  438.     my $self = shift;
  439.  
  440.     if ( $self->{current}{comp_source} =~ /\G<&(?!\|)/gcs )
  441.     {
  442.     if ( $self->{current}{comp_source} =~ /\G(.*?)&>/gcs )
  443.     {
  444.         my $call = $1;
  445.         $self->{current}{compiler}->component_call( call => $call );
  446.         $self->{current}{lines} += $call =~ tr/\n//;
  447.  
  448.         return 1;
  449.     }
  450.     else
  451.     {
  452.         $self->throw_syntax_error("'<&' without matching '&>'");
  453.     }
  454.     }
  455. }
  456.  
  457.  
  458. sub match_comp_content_call
  459. {
  460.     my $self = shift;
  461.  
  462.     if ( $self->{current}{comp_source} =~ /\G<&\|/gcs )
  463.     {
  464.     if ( $self->{current}{comp_source} =~ /\G(.*?)&>/gcs )
  465.     {
  466.         my $call = $1;
  467.         $self->{current}{compiler}->component_content_call( call => $call );
  468.         $self->{current}{lines} += $call =~ tr/\n//;
  469.  
  470.         return 1;
  471.     }
  472.     else
  473.     {
  474.         $self->throw_syntax_error("'<&|' without matching '&>'");
  475.     }
  476.     }
  477. }
  478.  
  479. sub match_comp_content_call_end
  480. {
  481.     my $self = shift;
  482.  
  483.     if ( $self->{current}{comp_source} =~ m,\G</&>,gc )
  484.     {
  485.         $self->{current}{compiler}->component_content_call_end;
  486.  
  487.         return 1;
  488.     }
  489. }
  490.  
  491. sub match_perl_line
  492. {
  493.     my $self = shift;
  494.  
  495.     if ( $self->{current}{comp_source} =~ /\G(?<=^)%([^\n]*)(?:\n|\z)/gcm )
  496.     {
  497.     $self->{current}{compiler}->perl_line( line => $1 );
  498.     $self->{current}{lines}++;
  499.  
  500.     return 1;
  501.     }
  502. }
  503.  
  504. sub match_text
  505. {
  506.     my $self = shift;
  507.     my $c = $self->{current};
  508.  
  509.     # Most of these terminator patterns actually belong to the next
  510.     # lexeme in the source, so we use a lookahead if we don't want to
  511.     # consume them.  We use a lookbehind when we want to consume
  512.     # something in the matched text, like the newline before a '%'.
  513.     if ( $c->{comp_source} =~ m{
  514.                 \G
  515.                 (.*?)         # anything, followed by:
  516.                 (
  517.                  (?<=\n)(?=%) # an eval line - consume the \n
  518.                  |
  519.                  (?=</?[%&])  # a substitution or block or call start or end
  520.                                               # - don't consume
  521.                  |
  522.                  \\\n         # an escaped newline  - throw away
  523.                  |
  524.                  \z           # end of string
  525.                 )
  526.                    }xcgs )
  527.     {
  528.     # Note: to save memory, it might be preferable to break very
  529.     # large $1 strings into several pieces and pass the pieces to
  530.     # compiler->text().  In my testing, this was quite a bit
  531.     # slower, though.  -Ken 2002-09-19
  532.     $c->{compiler}->text( text => $1 ) if length $1;
  533.         # Not checking definedness seems to cause extra lines to be
  534.         # counted with Perl 5.00503.  I'm not sure why - dave
  535.     $c->{lines} += tr/\n// foreach grep defined, ($1, $2);
  536.  
  537.     return 1;
  538.     }
  539.     
  540.     return 0;
  541. }
  542.  
  543. sub match_end
  544. {
  545.     my $self = shift;
  546.  
  547.     # $self->{current}{ending} is a qr// 'string'.  No need to escape.  It will
  548.     # also include the needed \G marker
  549.     if ( $self->{current}{comp_source} =~ /($self->{current}{ending})/gcs )
  550.     {
  551.     $self->{current}{lines} += $1 =~ tr/\n//;
  552.     return defined $1 && length $1 ? $1 : 1;
  553.     }
  554.     return 0;
  555. }
  556.  
  557. # goes from current pos, skips a newline if its the next character,
  558. # and then goes to the next newline.  Alternately, the caller can
  559. # provide a starting position.
  560. sub _next_line
  561. {
  562.     my $self = shift;
  563.     my $pos = shift;
  564.  
  565.     $pos = ( defined $pos ?
  566.          $pos :
  567.          ( substr( $self->{current}{comp_source}, pos($self->{current}{comp_source}), 1 ) eq "\n" ?
  568.            pos($self->{current}{comp_source}) + 1 :
  569.            pos($self->{current}{comp_source}) ) );
  570.  
  571.     my $to_eol = ( index( $self->{current}{comp_source}, "\n", $pos ) != -1 ?
  572.            ( index( $self->{current}{comp_source}, "\n" , $pos ) ) - $pos :
  573.            length $self->{current}{comp_source} );
  574.     return substr( $self->{current}{comp_source}, $pos, $to_eol );
  575. }
  576.  
  577. sub line_number
  578. {
  579.     my $self = shift;
  580.  
  581.     return $self->{current}{lines};
  582. }
  583.  
  584. sub name
  585. {
  586.     my $self = shift;
  587.  
  588.     return $self->{current}{name};
  589. }
  590.  
  591. sub throw_syntax_error
  592. {
  593.     my ($self, $error) = @_;
  594.  
  595.     HTML::Mason::Exception::Syntax->throw( error => $error,
  596.                        comp_name => $self->name,
  597.                        source_line => $self->_next_line,
  598.                        line_number => $self->line_number );
  599. }
  600.  
  601. 1;
  602.  
  603. __END__
  604.  
  605. =head1 NAME
  606.  
  607. HTML::Mason::Lexer - Generates events based on component source lexing
  608.  
  609. =head1 SYNOPSIS
  610.  
  611.   my $lexer = HTML::Mason::Lexer->new;
  612.  
  613.   $lexer->lex( comp_source => $source, name => $comp_name, compiler => $compiler );
  614.  
  615. =head1 DESCRIPTION
  616.  
  617. The Lexer works in tandem with the Compiler to turn Mason component
  618. source into something else, generally Perl code.
  619.  
  620. As the lexer finds component elements, like a tag or block, it calls
  621. the appropriate event methods in the compiler object it was given.
  622.  
  623. It has only a few public methods.
  624.  
  625. You can replace this lexer with one of your own simply by telling the
  626. Compiler to use a different lexer class.  Your lexer class simply
  627. needs to call the appropriate methods in the Component Class's API as
  628. it scans the source.
  629.  
  630. =head1 METHODS
  631.  
  632. The lexer has very few public methods.
  633.  
  634. =over 4
  635.  
  636. =item new
  637.  
  638. This method creates a new Lexer object.  This methods takes no
  639. parameters.
  640.  
  641. =item lex ( comp_source => ..., name => ..., compiler => ... )
  642.  
  643. This method tells the lexer to start scanning the given component
  644. source.  All of these parameters are required.  The C<name> parameter
  645. will be used in any error messages generated during lexing.  The
  646. C<compiler> object must be an object that implements the Mason
  647. Component API.
  648.  
  649. =item line_number
  650.  
  651. The current line number that the lexer has reached.
  652.  
  653. =item name
  654.  
  655. The name of the component currently being lexed.
  656.  
  657. =item throw_syntax_error ($error)
  658.  
  659. This throws an C<HTML::Mason::Exception::Syntax> error with the given
  660. error message as well as additional information about the component
  661. source.
  662.  
  663. This method is used by both the Lexer and the Compiler.
  664.  
  665. =back
  666.  
  667. =head1 SUBCLASSING
  668.  
  669. Any subclass of the lexer should declare itself to be a subclass of
  670. C<HTML::Mason::Lexer>, even if it plans to override all of its public
  671. methods.
  672.  
  673. If you want your subclass to work with the existing Compiler classes
  674. in Mason, you must implement the methods listed above.  If you plan to
  675. use a custom Compiler class that you're writing, you can do whatever
  676. you want.
  677.  
  678. =cut
  679.