File Coverage

blib/lib/JavaScript/Swell.pm
Criterion Covered Total %
statement 141 213 66.2
branch 92 138 66.6
condition 46 69 66.6
subroutine 28 33 84.8
pod 2 32 6.2
total 309 485 63.7


line stmt bran cond sub pod time code
1             package JavaScript::Swell;
2              
3 2     2   66629 use strict;
  2         4  
  2         15966  
4              
5             our $VERSION = '0.01';
6              
7             my @RE = qw(! != !== % %= & && &&= &= \( *= + += - -= -> . .. ... / /= : :: ; < << <<= <= = == === > >= >> >>= >>> >>>= ? @ \[ ^ ^= ^^ ^^= \{ | |= || ||= ~ abstract break case catch const continue debugger default delete do else enum export extends final finally for function goto if implements import in instanceof interface is namespace native new package return static switch synchronized throw throws transient try typeof use var volatile while with);
8             my @TS = qw(* ! != !== % %= & && &&= &= *= + += - -= -> .. ... / /= : :: < << <<= <= = == === > >= >> >>= >>> >>>= ? @ ^ ^= ^^ ^^= | |= || ||= ~);
9             my %RegularExpression;
10             my %RegularExpression_shortcut;
11             foreach (@RE) {
12             s/^\\//o;
13             my $word;
14             $RegularExpression{$_}++;
15             foreach (split(//)) {
16             $word .= $_;
17             $RegularExpression_shortcut{$word}++;
18             }
19             $RegularExpression_shortcut{'#'}++;
20             $RegularExpression_shortcut{','}++;
21             $RegularExpression{'#'}++;
22             $RegularExpression{','}++;
23             }
24             my %TERMSPACE;
25             foreach (@TS) {
26             s/^\\//o;
27             $TERMSPACE{$_}++;
28             }
29             $TERMSPACE{'#'}++;
30              
31             sub new {
32 2     2 0 3 my $class = shift;
33 2         29 bless {
34             source => '',
35             split_source => undef,
36             return_source => '',
37             parser_state => {
38             line => 0,
39             method => '',
40             re_word => '',
41             quote => '',
42             indent => 0,
43             cursor => 0,
44             parentheses_nest => 0,
45             is_linehead => 0,
46             squishmode => 0,
47             charlast => '',
48             },
49             }, $class;
50             }
51              
52              
53             #setter or getter
54             sub source {
55 4     4 0 5 my $self = shift;
56 4 100       10 if (@_) {
57 2         4 $self->{source} = shift;
58 2         6 $self->{source} =~ s/\r\n/\n/go;
59 2         26 my @ss = split(//, $self->{source});
60 2         9 $self->{split_source} = \@ss;
61 2         4 $self->{return_source} = '';
62             }
63 4         41 $self->{return_source};
64             }
65 247     247 0 259 sub split_source {@{shift->{split_source}}}
  247         692  
66             sub get_char {
67 309     309 0 310 my $self = shift;
68              
69 309 100       791 return $self->{split_source}[$self->cursor] unless @_;
70 185 50       621 if ($_[0] =~ m/^\-{0,1}\d+$/) {
71 185 100 100     326 if ((0 <= ($self->cursor + $_[0]) && ($self->split_source + 0) > ($self->cursor + $_[0]))) {
72 180         352 return $self->{split_source}[$self->cursor + $_[0]];
73             } else {
74 5         14 return '';
75             }
76             } else {
77 0         0 return $self->{split_source}[$self->cursor];
78             }
79             }
80 62     62 0 265 sub get_charlast {shift->{parser_state}->{charlast}}
81             sub set_char {
82 60     60 0 75 my $self = shift;
83 60         74 my $c = shift;
84              
85 60 100       287 $self->{parser_state}->{charlast} = $1
86             if $c =~ /(.)$/;
87              
88 60 100       178 $self->set_re_word($c) unless @_;
89 60         151 $self->{return_source} .= $c;
90             }
91             sub set_lf {
92 9     9 0 11 my $self = shift;
93 9 100       17 return if $self->squishmode;
94 4         10 $self->set_char("\n" . (' ' x $self->indent));
95 4         9 $self->is_linehead(1);
96             }
97             sub set_re_word {
98 58     58 0 66 my $self = shift;
99 58         68 my $c = shift;
100              
101 58 100       165 return if $c =~ /\s/o;
102              
103 46 100       82 unless ($RegularExpression_shortcut{$self->re_word . $c}) {
104 36         70 $self->re_word($c);
105             } else {
106 10         16 $self->re_word($self->re_word . $c);
107             }
108             }
109 0     0 0 0 sub is_re_before {$RegularExpression{shift->re_word}}
110 130 100   130 0 140 sub is_linehead {my $self = shift;@_ ? $self->{parser_state}->{is_linehead} = shift:$self->{parser_state}->{is_linehead}}
  130         409  
111 130 100   130 0 172 sub squishmode {my $self = shift;@_ ? $self->{parser_state}->{squishmode} = shift:$self->{parser_state}->{squishmode}}
  130         712  
112              
113 6 100   6 0 8 sub indent {my $self = shift;@_ ? $self->{parser_state}->{indent} = shift:$self->{parser_state}->{indent}}
  6         26  
114 738 100   738 0 757 sub cursor {my $self = shift;@_ ? $self->{parser_state}->{cursor} = shift:$self->{parser_state}->{cursor}}
  738         2994  
115 64 100   64 0 88 sub method {my $self = shift;@_ ? $self->{parser_state}->{method} = shift:$self->{parser_state}->{method}}
  64         196  
116 2 50   2 0 3 sub quote {my $self = shift;@_ ? $self->{parser_state}->{quote} = shift:$self->{parser_state}->{quote}}
  2         8  
117 8 100   8 0 9 sub parentheses_nest {my $self = shift;@_ ? $self->{parser_state}->{parentheses_nest} = shift:$self->{parser_state}->{parentheses_nest}}
  8         45  
118 230 100   230 0 254 sub re_word {my $self = shift;@_ ? $self->{parser_state}->{re_word} = shift:$self->{parser_state}->{re_word}}
  230         1221  
119              
120 64     64 0 166 sub add_cursor {shift->{parser_state}->{cursor}++}
121 2     2 0 6 sub add_indent {shift->{parser_state}->{indent} += 2}
122 2     2 0 7 sub dec_indent {shift->{parser_state}->{indent} -= 2}
123 2     2 0 15 sub add_parentheses_nest {shift->{parser_state}->{parentheses_nest}++}
124 2     2 0 6 sub dec_parentheses_nest {shift->{parser_state}->{parentheses_nest}--}
125              
126              
127             #parser
128             sub init_parser {
129 2     2 0 4 my $self = shift;
130              
131 2         8 $self->quote('');
132 2         6 $self->indent(0);
133 2         5 $self->cursor(0);
134 2         6 $self->parentheses_nest(0);
135 2         5 $self->method('default');
136 2         5 $self->re_word('{');
137 2         6 $self->is_linehead(0);
138             }
139              
140             sub term_spacer {
141 41     41 0 52 my $self = shift;
142 41 50       75 my $c = @_ ? shift : $self->get_char;
143 41 50       67 my $c2 = @_ ? shift : $self->get_char(1);
144 41 50       93 my $c3 = @_ ? shift : $self->get_char(2);
145 41 50       122 my $c4 = @_ ? shift : $self->get_char(3);
146 41         99 my $cb = $self->get_char(-1);
147 41         98 my $cl = $self->get_charlast;
148              
149 41         67 my ($s1, $s2) = (1, 1);
150 41 100       71 ($s1, $s2) = (0, 0) if $self->squishmode;
151 41         53 my $m = '';
152             # $s1 = 0 if $cb =~ /[\s\(\[]/;
153 41 100       119 $s1 = 0 if $cl =~ /[\s\(\[]/;
154              
155 41         76 my $cc4 = "$c$c2$c3$c4";
156 41         55 my $cc3 = "$c$c2$c3";
157 41         48 my $cc2 = "$c$c2";
158              
159 41 50 66     347 if ($TERMSPACE{$cc4}) {
    50 100        
    50 66        
    100 66        
    100 66        
    100 100        
    50 66        
160 0         0 $m = $cc4;
161 0         0 $self->add_cursor;
162 0         0 $self->add_cursor;
163 0         0 $self->add_cursor;
164             # $s2 = 0 if $self->get_char(4) =~ /[\s\)\]]/ && $self->squishmode;
165             } elsif ($TERMSPACE{$cc3}) {
166 0         0 $m = $cc3;
167 0         0 $self->add_cursor;
168 0         0 $self->add_cursor;
169             ## $s2 = 0 if $c4 =~ /[\s\)\]]/;
170             } elsif ($TERMSPACE{$cc2}) {
171 0         0 $m = $cc2;
172 0         0 $self->add_cursor;
173             # $s2 = 0 if $c3 =~ /[\s\)\]]/ && $self->squishmode;
174             } elsif ($cc2 eq '++' || $cc2 eq '--') {
175 2         4 $m = $cc2;
176 2         4 ($s1, $s2) = (0, 0);
177 2         5 $self->add_cursor;
178             ## $s2 = 0 if $c3 =~ /[\s\)\]]/;
179             } elsif (((($self->re_word eq '=' || $self->re_word eq '(') && ($c eq '+' || $c eq '-') && $c2 =~ /^\d$/) || ($TERMSPACE{$c} && $TERMSPACE{$c2}))) {
180 3         6 $m = $c;
181 3         4 $s2 = 0;
182             # $s2 = 0 if $c2 =~ /[\s\)\]]/ && $self->squishmode;
183             } elsif ($TERMSPACE{$c}) {
184 3         7 $m = $c;
185             # $s2 = 0 if $c2 =~ /[\s\)\]]/ && $self->squishmode;
186             } elsif ($c eq ',') {
187 0         0 $m = $c;
188 0         0 $s1 = 0;
189             } else {
190 33         127 return 0;
191             }
192 8 100       44 $self->set_char(' ') if $s1;
193 8         18 $self->set_char($m);
194 8 100       44 $self->set_char(' ') if $s2;
195            
196 8         31 return 1;
197             }
198              
199             sub parser_default {
200 62     62 0 62 my $self = shift;
201 62         104 my $c = $self->get_char;
202 62         114 my $c2 = $self->get_char(1);
203              
204 62 100 66     211 return if $c =~ /\s/o && ($self->get_charlast =~ /\s/ || $c2 !~ /[_a-zA-Z0-9]/);
      66        
205              
206 53 50       114 if ($c eq '/') {
207 0 0       0 if ($c2 eq '*') {
    0          
    0          
208 0         0 $self->method('comment');
209 0         0 $self->add_cursor;
210 0         0 $self->add_indent;
211 0         0 $self->set_char('/*', 1);
212 0         0 $self->set_lf;
213 0         0 return;
214             } elsif ($c2 eq '/') {
215 0         0 $self->method('comment_line');
216 0         0 $self->add_cursor;
217 0 0       0 $self->set_char('//', 1) unless $self->squishmode;
218 0         0 return;
219             } elsif ($self->is_re_before) {
220 0         0 $self->method('regularexpression');
221 0         0 $self->set_char('/');
222 0         0 return;
223             }
224             }
225              
226 53         92 my $bword = $self->re_word;
227 53 50 66     502 if ($c =~ /\s/o && $c2 =~ /\s/o) {
    50 33        
    100 100        
    100 66        
    100 100        
    100 66        
    100 100        
    50          
    100          
    100          
    50          
228 0         0 $self->add_cursor;
229             } elsif ($c eq '"' || $c eq '\'') {
230 0         0 $self->method('quote');
231 0         0 $self->set_char($c, 1);
232 0         0 $self->quote($c);
233              
234              
235             } elsif ($c eq '(') {
236 2 100 66     14 $self->set_char(' ', 1)
237             if $bword =~ /^(case|catch|do|for|function|if|import|switch|throw|try|while|with)$/o && !$self->squishmode;
238 2         5 $self->set_char('(');
239 2         5 $self->add_parentheses_nest;
240             } elsif ($c eq ')') {
241 2 50       5 if ($self->parentheses_nest) {
242 2         5 $self->set_char(')');
243 2         5 $self->dec_parentheses_nest;
244             } else {
245 0         0 $self->set_char(')');
246             }
247 2 50       9 $self->set_char(' ') if $c2 =~ /[\_a-z-A-Z0-9]/;
248             } elsif ($c eq '{') {
249 2 100 66     16 $self->set_char(' ', 1)
250             if $bword =~ /^(case|catch|do|try|else|\))$/o && !$self->squishmode;
251 2         6 $self->add_indent;
252 2         5 $self->set_char('{');
253 2 50       7 $self->set_lf unless $c2 eq '}';
254             } elsif ($c eq '}') {
255 2         6 $self->dec_indent;
256 2         5 $self->set_lf;
257 2         5 $self->set_char('}');
258 2 50       7 if ($c2 eq ';') {
259 0         0 $self->add_cursor;
260 0         0 $self->set_char(';');
261             }
262 2 50       6 if ($c2 ne '}') {
263 2         11 $self->set_lf;
264             }
265             } elsif ($c eq ';') {
266 4         9 $self->set_char(';');
267 4 50 33     16 if ($self->parentheses_nest && !$self->squishmode) {
    100          
268 0         0 $self->set_char(' ');
269             } elsif ($c2 ne '}') {
270 3         6 $self->set_lf;
271             }
272             } elsif ($self->squishmode && $c eq 'i' && $bword eq 'else') {
273 0         0 $self->set_char(' ');
274 0         0 $self->set_char('i');
275             } elsif ($self->term_spacer($c, $c2)) {
276             } elsif ($self->squishmode && $c =~ /\s/o && ($self->get_charlast !~ /[_a-zA-Z0-9]/ || $c2 !~ /[_a-zA-Z0-9]/)) {
277             } elsif ($c ne "\n") {
278 30         65 $self->set_char($c);
279             }
280             }
281             sub parser_comment {
282 0     0 0 0 my $self = shift;
283 0         0 my $c = $self->get_char;
284 0         0 my $c2 = $self->get_char(1);
285              
286 0 0 0     0 if ($c eq '*' && $c2 eq '/') {
    0          
287 0         0 $self->method('default');
288 0         0 $self->add_cursor;
289 0         0 $self->dec_indent;
290 0         0 $self->set_lf;
291 0         0 $self->set_char('*/', 1);
292 0         0 $self->set_lf;
293             } elsif ($c eq "\n") {
294 0         0 $self->set_lf;
295             } else {
296 0         0 $self->set_char($c, 1);
297             }
298             }
299             sub parser_comment_line {
300 0     0 0 0 my $self = shift;
301 0         0 my $c = $self->get_char;
302              
303 0 0       0 if ($c eq "\n") {
304 0         0 $self->set_lf;
305 0         0 $self->method('default');
306             } else {
307 0 0       0 $self->set_char($c, 1) unless $self->squishmode;
308             }
309             }
310             sub parser_quote {
311 0     0 0 0 my $self = shift;
312 0         0 my $c = $self->get_char;
313              
314 0         0 $self->set_char($c, 1);
315 0 0       0 if ($c eq $self->quote) {
316 0         0 $self->quote('');
317 0         0 $self->method('default');
318             }
319             }
320             sub parser_regularexpression {
321 0     0 0 0 my $self = shift;
322 0         0 my $c = $self->get_char;
323              
324 0 0 0     0 if ($c eq '/' || $c eq "\n") {
325 0         0 $self->set_char($c);
326 0         0 $self->method('default');
327             } else {
328 0         0 $self->set_char($c, 1);
329             }
330             }
331              
332             sub parser {
333 2     2 0 4 my $self = shift;;
334 2 50       11 $self->source(shift) if @_;
335              
336 2         6 $self->init_parser;
337              
338 2         6 while ($self->cursor < $self->split_source) {
339 62         132 my $c = $self->get_char;
340 62 50 66     164 if ($c eq '\\') {
    50          
341 0         0 $self->set_char($c, 1);
342 0         0 $self->set_char($self->get_char(1), 1);
343 0         0 $self->add_cursor;
344             } elsif ($self->is_linehead && ($c =~ /\s/)) {
345             } else {
346 62         104 $self->is_linehead(0);
347 62         103 my $method = 'parser_' . $self->method;
348 62         157 $self->$method();
349             }
350 62         133 $self->add_cursor;
351             }
352              
353 2         5 $self->source;
354             }
355              
356             sub swell {
357 1     1 1 15 my $self;
358 1 50       6 if (ref($_[0]) eq __PACKAGE__) {
359 0         0 $self = shift;
360             } else {
361 1         7 $self = shift->new;
362             }
363 1         8 $self->squishmode(0);
364 1         6 $self->parser(@_);
365             }
366              
367             sub squish {
368 1     1 1 3 my $self;
369 1 50       5 if (ref($_[0]) eq __PACKAGE__) {
370 0         0 $self = shift;
371             } else {
372 1         4 $self = shift->new;
373             }
374 1         4 $self->squishmode(1);
375 1         3 $self->parser(@_);
376             }
377              
378             1;
379             __END__