File Coverage

blib/lib/Text/PORE/template_lexer.pl
Criterion Covered Total %
statement 47 60 78.3
branch 38 48 79.1
condition 6 9 66.6
subroutine 5 6 83.3
pod 0 5 0.0
total 96 128 75.0


line stmt bran cond sub pod time code
1             # template_lexer.pl
2             # perl library associated with template.y (the template parser definition)
3             #
4             # NOTE: extensive use of Perl5 regular expressions is made in this
5             # file. see perlre(1)
6            
7             package Text::PORE::Parser;
8 1     1   876 use English;
  1         3  
  1         10  
9            
10             my $TAG_PREFIX = "PORE";
11            
12             my $lexer_token;
13             my $lexer_buffer = '';
14             my $lineno = 1;
15            
16             # yyerror
17             # displays error messages
18             # called by yyparse
19             sub yyerror {
20 0     0 0 0 my ($msg) = @_;
21 0         0 print STDERR "$lineno: $msg at '$yylval'\n";
22             }
23            
24             # countlines
25             # increments the line counter used by yyerror
26             sub countlines {
27 505     505 0 850 my ($string) = shift;
28            
29 505 100       1410 if (defined $string) {
30 348         1568 $lineno += ($string =~ s/\n/$1/gos);
31             }
32             }
33            
34             # returns the current line number (in the template) for debugging purposes
35             sub getlineno {
36 132     132 0 10089 return $lineno;
37             }
38            
39             sub setInput {
40 6     6 0 20 my ($input) = shift;
41            
42 6         17 $Parser::INPUT = $input;
43             }
44            
45             # yylex
46             # supplies tokens for yyparse
47             # NOTE: no escape sequences are defined
48             # (don't put a '>' within a tag, etc.)
49            
50             sub yylex {
51 321     321 0 12569 my $input;
52            
53 321         578 while (1) {
54 365 100       831 if ($INTAG) { # Are we inside a PORE tag?
55 190         439 $lexer_buffer =~ s/^\s+//; # ignore whitespace in tags
56 190         380 countlines($MATCH);
57            
58 190 100       2092 if ($lexer_buffer =~ s/^$TAG_PREFIX.(\w+)//si) {
    100          
    100          
    100          
    50          
    100          
    100          
    50          
59 53         161 $yylval = lc($1);
60 53 100       244 if ($yylval eq "if") { $lexer_token = 'IF_ID'; }
  28 100       166  
    100          
    50          
    100          
    50          
    0          
    0          
61 3         9 elsif ($yylval eq "else") { $lexer_token = 'ELSE_ID'; }
62 2         4 elsif ($yylval eq "context") { $lexer_token = 'CONTEXT_ID'; }
63 0         0 elsif ($yylval eq "link") { $lexer_token = 'LINK_ID'; }
64 4         8 elsif ($yylval eq "list") { $lexer_token = 'LIST_ID'; }
65 16         32 elsif ($yylval eq "render") { $lexer_token = 'RENDER_ID'; }
66 0         0 elsif ($yylval eq "ref") { $lexer_token = 'REF_ID'; }
67 0         0 elsif ($yylval eq "table") { $lexer_token = 'TABLE_ID'; }
68 0         0 else { yyerror("Unrecognized tag"); }
69             } elsif ($lexer_buffer =~ s/^\///s) {
70 17         43 $yylval = $MATCH; # Match slash ('/')
71 17         40 $lexer_token = 'SLASH';
72             } elsif ($lexer_buffer =~ s/^(\w+)//s) {
73 33         58 $yylval = $MATCH; # Match an identifier
74 33         51 $lexer_token = 'NAME';
75             } elsif ($lexer_buffer =~ s/^=\s*([\.\w]+)//s) {
76 15         28 $yylval = $1; # Match a value ('= val')
77 15         30 $lexer_token = 'VAL';
78             } elsif ($lexer_buffer =~ s/^=\s*([\'\"])\1//s) {
79 0         0 $yylval = $1; # Match a value ('=""')
80 0         0 $lexer_token = 'VAL';
81             } elsif ($lexer_buffer =~ s/^=\s*([\'\"])(([^\\]|\\.)*?)\1//s) {
82 18         40 $yylval = $2; # Match a value ('= "long val"')
83 18         36 $lexer_token = 'VAL';
84             } elsif ($lexer_buffer =~ s/^>//s) {
85 53         86 $yylval = $MATCH; # Match a close_bracket ('>')
86 53         91 $lexer_token = 'CLOSE_BRACKET';
87             } elsif ($lexer_buffer =~ s/^
88 0         0 $yylval = $MATCH;
89 0         0 $lexer_token = 'OPEN_BRACKET';
90             }
91            
92             } else { # Not in a PORE tag
93 175 100 66     3141 if (defined $lexer_buffer &&
    100 66        
94             $lexer_buffer =~ s/^<(?=\/?$TAG_PREFIX\.)//si) {
95 53         106 $yylval = $MATCH; # Match an open_bracket ('<')
96 53         108 $lexer_token = 'OPEN_BRACKET';
97             } elsif (defined $lexer_buffer &&
98             $lexer_buffer =~ s/^.+?(?=<\/?$TAG_PREFIX\.)|^.+//si) {
99 73         251 $yylval = $MATCH; # Open_bracket followned by
100 73         316 $lexer_token = 'FREETEXT';
101             }
102             }
103            
104             # Return match
105 365 100       682 if ($lexer_token) {
106 315         17570 my ($token_val) = eval "$$lexer_token";
107 315         982 $lexer_token = undef;
108 315         611 countlines($yylval);
109 315         1013 return $token_val;
110            
111             # If we didn't match anything, grab more input
112             } else {
113 50         199 $input = $Parser::INPUT->readLine();
114            
115 50 100 66     407 if (!(defined $input) || !length($input)) {
116             # if no more input, and unrecognized token, error
117 6 50       11 if ($lexer_buffer) {
118 0         0 $lexer_buffer =~ s/\n.*$/.../s;
119 0         0 print STDERR "$lineno: Unrecognized token " .
120             "[$lexer_buffer].\nAborting with errors\n";
121 0         0 exit;
122             } else { # if no more input, and no more tokens, we're done
123 6         18 return 0;
124             }
125             }
126 44 50       284 $lexer_buffer .= $input if defined $input;
127             }
128             }
129             }
130            
131             1;