| File: | blib/lib/CSS/Parse/Match.pm |
| Coverage: | 96.6% |
| line | stmt | bran | cond | sub | time | code |
|---|---|---|---|---|---|---|
| 1 | package CSS::Parse::Match; | |||||
| 2 | ||||||
| 3 | 14 14 14 | 53 22 57 | use strict; | |||
| 4 | 14 14 14 | 63 24 66 | use warnings; | |||
| 5 | 14 14 14 | 145 24 63 | use Time::HiRes qw(gettimeofday tv_interval); | |||
| 6 | ||||||
| 7 | sub new { | |||||
| 8 | 8946 | 28193 | my ($class, $op, $tokens, $token_pc) = @_; | |||
| 9 | ||||||
| 10 | 8946 | 27348 | my $self = bless {}, $class; | |||
| 11 | ||||||
| 12 | 8946 | 25420 | $self->{op} = $op; | |||
| 13 | 8946 | 25608 | $self->{submatches} = []; | |||
| 14 | 8946 | 25276 | $self->{matched_tokens} = []; | |||
| 15 | 8946 | 22838 | $self->{subrule} = undef; | |||
| 16 | 8946 | 21858 | $self->{matched_text} = undef; | |||
| 17 | ||||||
| 18 | #my $t0 = [gettimeofday]; | |||||
| 19 | #@{$self->{tokens}} = @{$tokens} if ref $tokens eq 'ARRAY'; | |||||
| 20 | #my $t1 = [gettimeofday]; | |||||
| 21 | #print "Copy took ".(1000*tv_interval($t0, $t1))." ms\n"; | |||||
| 22 | ||||||
| 23 | 8946 | 22320 | $self->{token_pc} = $token_pc; | |||
| 24 | 8946 | 21976 | $self->{tokens} = $tokens; | |||
| 25 | ||||||
| 26 | 8946 | 24752 | return $self; | |||
| 27 | } | |||||
| 28 | ||||||
| 29 | sub add_submatch { | |||||
| 30 | 3045 | 8275 | my ($self, $submatch) = @_; | |||
| 31 | ||||||
| 32 | 3045 3045 | 4985 9819 | push @{$self->{submatches}}, $submatch; | |||
| 33 | ||||||
| 34 | 3045 | 13556 | $self->{token_pc} = $submatch->{token_pc}; | |||
| 35 | } | |||||
| 36 | ||||||
| 37 | sub add_matched_token { | |||||
| 38 | 1023 | 2881 | my ($self, $token) = @_; | |||
| 39 | ||||||
| 40 | 1023 1023 | 1854 4192 | push @{$self->{matched_tokens}}, $token; | |||
| 41 | } | |||||
| 42 | ||||||
| 43 | sub shift_token { | |||||
| 44 | 5694 | 14839 | my ($self) = @_; | |||
| 45 | ||||||
| 46 | 5694 | 13231 | $self->{token_pc}++; | |||
| 47 | 5694 | 28226 | return $self->{tokens}->[$self->{token_pc}-1]; | |||
| 48 | } | |||||
| 49 | ||||||
| 50 | sub unshift_token { | |||||
| 51 | 4549 | 11296 | my ($self) = @_; | |||
| 52 | ||||||
| 53 | 4549 | 12973 | $self->{token_pc}--; | |||
| 54 | ||||||
| 55 | # we assume here that the token we have to unshift is the one we used to have :) | |||||
| 56 | #unshift @{$_[0]->{tokens}}, $_[1]; | |||||
| 57 | } | |||||
| 58 | ||||||
| 59 | sub scrub { | |||||
| 60 | 2727 | 6380 | my ($self) = @_; | |||
| 61 | ||||||
| 62 | 2727 | 5926 | delete $self->{tokens}; | |||
| 63 | 2727 | 5663 | delete $self->{token_pc}; | |||
| 64 | 2727 | 5857 | delete $self->{op}; | |||
| 65 | ||||||
| 66 | 2727 2727 | 4405 12663 | for my $submatch (@{$self->{submatches}}){ | |||
| 67 | ||||||
| 68 | 2710 | 6850 | $submatch->scrub; | |||
| 69 | } | |||||
| 70 | } | |||||
| 71 | ||||||
| 72 | sub dump { | |||||
| 73 | 2 | 7 | my ($self) = @_; | |||
| 74 | ||||||
| 75 | 2 | 7 | return $self->_dump_internal(''); | |||
| 76 | } | |||||
| 77 | ||||||
| 78 | sub _dump_internal { | |||||
| 79 | 3 | 61 | my ($self, $prefix) = @_; | |||
| 80 | ||||||
| 81 | 3 3 | 5 11 | my $subs = scalar @{$self->{submatches}}; | |||
| 82 | 3 3 | 6 10 | my $matches = scalar @{$self->{matched_tokens}}; | |||
| 83 | ||||||
| 84 | 3 | 23 | return '' unless $subs || $matches; | |||
| 85 | ||||||
| 86 | 2 | 7 | my $text = $self->_dump_node_text; | |||
| 87 | ||||||
| 88 | 2 | 9 | my $buffer = "$prefix$self->{op} \"$text\" \{\n"; | |||
| 89 | ||||||
| 90 | 2 2 | 4 8 | for my $submatch (@{$self->{submatches}}){ | |||
| 91 | ||||||
| 92 | 1 | 6 | $buffer .= $submatch->_dump_internal("$prefix\t"); | |||
| 93 | } | |||||
| 94 | ||||||
| 95 | 2 2 | 5 8 | for my $token (@{$self->{matched_tokens}}){ | |||
| 96 | ||||||
| 97 | 1 | 8 | $buffer .= "$prefix\t$token->{type}: \"$token->{content}\"\n"; | |||
| 98 | } | |||||
| 99 | ||||||
| 100 | 2 | 5 | $buffer .= "$prefix}\n"; | |||
| 101 | ||||||
| 102 | 2 | 7 | return $buffer; | |||
| 103 | } | |||||
| 104 | ||||||
| 105 | sub _dump_node_text { | |||||
| 106 | 3 | 7 | my ($self) = @_; | |||
| 107 | ||||||
| 108 | 3 | 7 | my $buffer = ''; | |||
| 109 | ||||||
| 110 | 3 3 | 6 12 | for my $submatch (@{$self->{submatches}}){ | |||
| 111 | ||||||
| 112 | 1 | 5 | $buffer .= $submatch->_dump_node_text; | |||
| 113 | } | |||||
| 114 | ||||||
| 115 | 3 3 | 6 11 | for my $token (@{$self->{matched_tokens}}){ | |||
| 116 | ||||||
| 117 | 2 | 9 | $buffer .= $token->{content}; | |||
| 118 | } | |||||
| 119 | ||||||
| 120 | 3 | 10 | return $buffer; | |||
| 121 | } | |||||
| 122 | ||||||
| 123 | sub reduce { | |||||
| 124 | 2725 | 6550 | my ($self) = @_; | |||
| 125 | ||||||
| 126 | # | |||||
| 127 | # first reduce our own submatches | |||||
| 128 | # | |||||
| 129 | ||||||
| 130 | 2725 | 4892 | my $subrules = 0; | |||
| 131 | ||||||
| 132 | 2725 2725 | 4347 9626 | for my $submatch (@{$self->{submatches}}){ | |||
| 133 | ||||||
| 134 | 2709 | 7119 | $submatch->reduce; | |||
| 135 | ||||||
| 136 | 2709 | 12417 | if (defined $submatch->{subrule}){ | |||
| 137 | ||||||
| 138 | 570 | 1708 | $subrules++; | |||
| 139 | } | |||||
| 140 | } | |||||
| 141 | ||||||
| 142 | ||||||
| 143 | # | |||||
| 144 | # remove any submatches which don't match any content | |||||
| 145 | # | |||||
| 146 | ||||||
| 147 | 2725 | 7207 | my $old_submatches = $self->{submatches}; | |||
| 148 | 2725 | 7355 | $self->{submatches} = []; | |||
| 149 | ||||||
| 150 | 2725 2725 | 4850 7587 | for my $submatch (@{$old_submatches}){ | |||
| 151 | ||||||
| 152 | 2709 | 10054 | if (length $submatch->{matched_text}){ | |||
| 153 | ||||||
| 154 | 2370 2370 | 3841 10192 | push @{$self->{submatches}}, $submatch; | |||
| 155 | } | |||||
| 156 | } | |||||
| 157 | ||||||
| 158 | ||||||
| 159 | # | |||||
| 160 | # collect together our output | |||||
| 161 | # | |||||
| 162 | ||||||
| 163 | 2725 | 7129 | $self->{matched_text} = ''; | |||
| 164 | ||||||
| 165 | 2725 2725 | 4702 9206 | for my $token (@{$self->{matched_tokens}}){ | |||
| 166 | ||||||
| 167 | 944 | 4056 | $self->{matched_text} .= $token->{content}; | |||
| 168 | } | |||||
| 169 | ||||||
| 170 | # this line is a bit dodgy as it deletes the original token list which we *may* want | |||||
| 171 | 2725 | 6617 | delete $self->{matched_tokens}; | |||
| 172 | ||||||
| 173 | 2725 2725 | 4495 9054 | for my $submatch (@{$self->{submatches}}){ | |||
| 174 | ||||||
| 175 | 2370 | 9809 | $self->{matched_text} .= $submatch->{matched_text}; | |||
| 176 | } | |||||
| 177 | ||||||
| 178 | ||||||
| 179 | # | |||||
| 180 | # now reduce ourselves. | |||||
| 181 | # if all of our submatches are not subrules, fold them into ourselves | |||||
| 182 | # | |||||
| 183 | ||||||
| 184 | 2725 | 7942 | unless ($subrules){ | |||
| 185 | ||||||
| 186 | 2328 | 5794 | my $old_submatches = $self->{submatches}; | |||
| 187 | 2328 | 6491 | $self->{submatches} = []; | |||
| 188 | ||||||
| 189 | 2328 2328 | 3967 7230 | for my $submatch (@{$old_submatches}){ | |||
| 190 | ||||||
| 191 | 1660 1660 | 2797 7715 | for my $subsubmatch (@{$submatch->{submatches}}){ | |||
| 192 | ||||||
| 193 | 375 375 | 589 1977 | push @{$self->{submatches}}, $subsubmatch; | |||
| 194 | } | |||||
| 195 | ||||||
| 196 | # | |||||
| 197 | # this loop wont find anything as we deleted our own | |||||
| 198 | # matched token list on line 156 (and we called this | |||||
| 199 | # method on our submatches already) | |||||
| 200 | # | |||||
| 201 | ||||||
| 202 | #for my $subtoken (@{$submatch->{matched_tokens}}){ | |||||
| 203 | # push @{$self->{matched_tokens}}, $subtoken; | |||||
| 204 | #} | |||||
| 205 | } | |||||
| 206 | } | |||||
| 207 | } | |||||
| 208 | ||||||
| 209 | sub remove_anon_matches { | |||||
| 210 | 66 | 173 | my ($self) = @_; | |||
| 211 | ||||||
| 212 | ||||||
| 213 | # | |||||
| 214 | # this function removes unnamed match rules - in general we only care about the named stuff, | |||||
| 215 | # since everything else tends to filler. this makes walking the tree a lot simpler. | |||||
| 216 | # | |||||
| 217 | ||||||
| 218 | ||||||
| 219 | # | |||||
| 220 | # first, reduce our children | |||||
| 221 | # | |||||
| 222 | ||||||
| 223 | 66 66 | 107 220 | for my $submatch (@{$self->{submatches}}){ | |||
| 224 | ||||||
| 225 | 62 | 161 | $submatch->remove_anon_matches; | |||
| 226 | } | |||||
| 227 | ||||||
| 228 | ||||||
| 229 | # | |||||
| 230 | # remove any children which have no name and no children of their own | |||||
| 231 | # | |||||
| 232 | ||||||
| 233 | 66 | 194 | my $new_subs = []; | |||
| 234 | ||||||
| 235 | 66 66 | 162 218 | for my $submatch (@{$self->{submatches}}){ | |||
| 236 | ||||||
| 237 | 62 | 193 | if (defined $submatch->{subrule}){ | |||
| 238 | ||||||
| 239 | 32 32 | 54 110 | push @{$new_subs}, $submatch; | |||
| 240 | ||||||
| 241 | }else{ | |||||
| 242 | ||||||
| 243 | 30 30 | 42 140 | if (scalar @{$submatch->{submatches}}){ | |||
| 244 | ||||||
| 245 | 0 0 | 0 0 | for my $child_of_child (@{$submatch->{submatches}}){ | |||
| 246 | ||||||
| 247 | 0 0 | 0 0 | push @{$new_subs}, $child_of_child; | |||
| 248 | } | |||||
| 249 | } | |||||
| 250 | } | |||||
| 251 | } | |||||
| 252 | ||||||
| 253 | 66 | 259 | $self->{submatches} = $new_subs; | |||
| 254 | ||||||
| 255 | } | |||||
| 256 | ||||||
| 257 | sub tokens_left { | |||||
| 258 | 25 25 | 93 160 | return scalar(@{$_[0]->{tokens}}) - $_[0]->{token_pc}; | |||
| 259 | } | |||||
| 260 | ||||||
| 261 | 1; | |||||
| 262 | ||||||