4 # Reformats your php source code
6 # $Id: phpindent,v 1.1 2002/05/20 12:54:03 weasel Exp $
9 # Depends: Parse::RecDescent
12 # (c) 2002 Florian Reitmeir <squat@riot.org>
13 # Peter Palfrader <peter@palfrader.org>
15 # This program is free software; you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation; either version 2 of the License, or
18 # (at your option) any later version.
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 # Usage: phpindent < orig.php > new.php
34 # - It might corrupt your code
35 # - It might not even work at all
36 # - It does not understand all of php
37 # - It's damn slow (several hours for one of our 800 line examples on a gHz
39 # - But it was fun to write and merely to test out Parse::RecDescent
41 # It was just a proof of concept - don't use it in production
43 # Did I mention it was slow?
46 # Q: So why did you write it?
47 # A: It was an ad hoc quick hack which went out of control but was
50 # Q: So are there any real php indenters?
51 # A: We didn't find any which is why we tried this nonsense at all.
52 # If you find any just let us know and we will link to them.
54 # Q: Will you improve this indenter/fix bugs I report?
55 # A: Probably not. But if you happen to have lots of time we would
56 # welcome a patch or two.
58 # Q: You know your grammar sucks?
62 #######################################################################
67 my ($class, %args) = @_;
71 #######################################################################
72 package MyBinaryOperator
;
80 $self->{left
}->reprint(),
82 $self->{right
}->reprint();
85 #######################################################################
86 package MyPostOperator
;
94 $self->{left
}->reprint(),
98 #######################################################################
99 package MyPreOperator
;
100 @ISA = qw( MyToken );
108 $self->{right
}->reprint();
111 #######################################################################
113 @ISA = qw( MyToken );
124 #######################################################################
126 @ISA = qw( MyToken );
137 #######################################################################
139 @ISA = qw( MyToken );
143 my ($self, %args) = @_;
144 my $il = $args{'indent'} || 1;
145 my $i = "\t" x
($il -1 );
147 my $value = $self->{'value'};
148 $value =~ s
,#\s*,# ,;
149 $value =~ s
,//\s
*,\n\n$i// ,;
154 #######################################################################
155 package MyCommentMultiLine
;
156 @ISA = qw( MyToken );
160 my ($self, %args) = @_;
161 my $il = $args{'indent'}-1 || 0;
164 my $value = $self->{'value'};
165 $value =~ s
,/\
*\s
*\n?
,,;
166 $value =~ s
,\n?\s
*\
*/,,;
167 my @lines = map { s/^\s*\*?[ \t]*/$i * /; $_ } split /\n/, $value;
168 unshift @lines, "/*";
169 push @lines, "$i */";
176 #######################################################################
177 package MyCommentDoc
;
178 @ISA = qw( MyToken );
182 my ($self, %args) = @_;
183 my $il = $args{'indent'}-1 || 0;
186 my $value = $self->{'value'};
187 $value =~ s
,^/\
*\
*[ \t]*\n?
,,;
188 $value =~ s
,\n?
[ \t]*\
*/$,,;
190 my @lines = split /\n/, $value;
194 my ($leadwhitespace) = ($_ =~ /^(\s*)/);
195 $maxwhitespace = (!defined ($maxwhitespace) || length($leadwhitespace) < $maxwhitespace) ?
196 length($leadwhitespace) :
199 my $leadwhitespace = " " x
$maxwhitespace;
200 @lines = map { s/^$leadwhitespace//; s/^/$i /; $_ } @lines;
202 unshift @lines, "/**";
203 push @lines, "$i */";
210 #######################################################################
211 package MyConditionalBlock
;
212 @ISA = qw( MyToken );
216 my ($self, %args) = @_;
217 my $il = $args{'indent'} || 0;
220 my $block = $self->{block
}->reprint(indent
=> $il, noend
=>1);
221 if ($block =~ /^\s*\{/) {
222 $block = "\t" x
($il-1) . $block;
225 $block = "\t" x
($il) . $block;
231 if ($self->{type
} eq 'ifelse') {
232 $elseblock = $self->{elseblock
}->reprint(indent
=> $il, noend
=>1);
233 if ($elseblock =~ /^\s*\{/) {
234 $elseblock = "\t" x
($il-1) . $elseblock;
237 $elseblock = "\t" x
($il) . $elseblock;
242 if ($self->{type
} eq 'if' || $self->{type
} eq 'while') {
246 $self->{condition
}->reprint().
249 ($isblock ?
";\n" : "");
250 } elsif ($self->{type
} eq 'ifelse') {
254 $self->{condition
}->reprint().
257 ($elseisblock ?
"\n" : "").
258 "\t"x
($il-1) . "else\n".
260 ($elseisblock ?
";\n" : "");
261 } elsif ($self->{type
} eq 'dowhile') {
266 $self->{condition
}->reprint().
268 } elsif ($self->{type
} eq 'for') {
272 $self->{part1
}->reprint().
274 $self->{part2
}->reprint().
276 $self->{part3
}->reprint().
279 ($isblock ?
";\n" : "");
280 } elsif ($self->{type
} eq 'foreach') {
284 $self->{part1
}->reprint().
286 $self->{part2
}->reprint().
289 ($isblock ?
";\n" : "");
294 #######################################################################
296 @ISA = qw( MyToken );
300 my ($self, %args) = @_;
301 my $il = $args{'indent'} || 1;
304 my $statements = join (", ", map { $_->reprint() } @
{$self->{'statements'}});
310 #######################################################################
312 @ISA = qw( MyToken );
316 my ($self, %args) = @_;
317 my $il = $args{'indent'} || 1;
321 $self->{name
}->reprint().
323 ((defined $self->{params
}) ?
$self->{params
}->reprint() : "").
327 #######################################################################
329 @ISA = qw( MyToken );
333 my ($self, %args) = @_;
334 my $il = $args{'indent'} || 1;
337 my $statements = join ($i, map { $_->reprint(indent
=> $il + 1) } @
{$self->{'statements'}});
339 $statements = $i.$statements if ( substr($statements,0,1) ne "\n" );
342 ((defined $args{'nobraces'}) ?
"" : "{\n").
345 ((defined $args{'nobraces'}) ?
"" : "}").
346 ((defined $args{'noend'}) ?
"" : ";\n");
349 #######################################################################
350 package MyFunctionDefinition
;
351 @ISA = qw( MyToken );
355 my ($self, %args) = @_;
357 my $il = $args{'indent'} || 1;
358 my $i = "\t" x
($il-1);
363 $self->{'header'}->reprint(). "\n".
364 $i.$self->{'block'}->reprint(indent
=> $il)."\n";
370 #######################################################################
374 use Parse
::RecDescent
;
383 Script
: /<\?(php)?/ Block
'?>' { MyAtom
->new ( value
=> "<?\n" . $item[2]->reprint(nobraces
=>1) ."?>\n" ) }
385 GroupedBlock
: '{' Block
'}' /;?/ { MyBlock
->new ( statements
=> [ @
{$item[2]->{'statements'}} ] ) }
387 Block
: Statement Block
{ MyBlock
->new ( statements
=> [ $item[1], @
{$item[2]->{'statements'}} ] ) }
388 | Statement
{ MyBlock
->new ( statements
=> [ $item[1] ] ) }
390 Statement
: Expression
';' { MyStatement
->new ( value
=> $item[1]->reprint() ) }
391 | ';' { MyStatement
->new ( value
=> '' ) }
392 | GroupedBlock
';' { $item[1] }
403 FunctionDefinition
: "function" FunctionCall GroupedBlock
404 { MyFunctionDefinition
->new ( header
=> $item[2], block
=> $item[3] ) }
407 IfThenElseBlock
: "if" "(" Expression
")" Statement
"else" Statement
408 { MyConditionalBlock
->new ( type
=> 'ifelse',
409 condition
=> $item[3],
411 elseblock
=> $item[7] ) }
412 IfBlock
: "if" "(" Expression
")" Statement
413 { MyConditionalBlock
->new ( type
=> 'if',
414 condition
=> $item[3],
415 block
=> $item[5] ) }
416 WhileBlock
: "while" "(" Expression
")" Statement
417 { MyConditionalBlock
->new ( type
=> 'while',
418 condition
=> $item[3],
419 block
=> $item[5] ) }
420 DoWhileBlock
: "do" GroupedBlock
"while" "(" Expression
")" ";"
421 { MyConditionalBlock
->new ( type
=> 'dowhile',
422 condition
=> $item[5],
423 block
=> $item[2] ) }
424 ForLoop
: "for" "(" Expression
";" Expression
";" Expression
")" Statement
425 { MyConditionalBlock
->new ( type
=> 'for',
429 block
=> $item[9] ) }
430 ForEachLoop
: "foreach" "(" Expression
"as" Expression
")" Statement
431 { MyConditionalBlock
->new ( type
=> 'foreach',
434 block
=> $item[7] ) }
435 Expression
: "(" Expression
")" { $item[2] }
436 | FunctionCall Operator Expression
437 { MyBinaryOperator
->new ( left
=>$item[1], operator
=>$item[2], right
=>$item[3] ) }
438 | Atom Operator Expression
439 { MyBinaryOperator
->new ( left
=>$item[1], operator
=>$item[2], right
=>$item[3] ) }
440 | Atom Operator
{ MyPostOperator
->new ( left
=>$item[1], operator
=>$item[2] ) }
441 | PreOperator Expression
{ MyPreOperator
->new ( right
=>$item[2], operator
=>$item[1] ) }
451 CommentHash
: /#.*?$/m { MyComment
->new ( value
=> $item[1] ) }
452 CommentSlash
: /\/\
/.*?$/m { MyComment
->new ( value
=> $item[1] ) }
453 CommentDoc
: /\/\
*\
*.*?\
*\
//s { MyCommentDoc
->new ( value
=> $item[1] ) }
454 CommentMultiLine
: /\/\
*.*?\
*\
//s { MyCommentMultiLine
->new ( value
=> $item[1] ) }
497 FunctionCall
: Atom
"(" FunctionParameter
")"
498 { MyFunction
->new ( name
=> $item[1], params
=> $item[3] ) }
500 { MyFunction
->new ( name
=> $item[1] ) }
508 FunctionParameter
: Expression
"," FunctionParameter
509 { MyParam
->new ( statements
=> [ $item[1], @
{$item[3]->{'statements'}} ] ) }
510 | Expression
{ MyParam
->new ( statements
=> [ $item[1] ] ) }
513 Variable
: '$' Identifier Array
514 { MyAtom
->new ( value
=> '$'.$item[2]->reprint() . $item[3]->reprint() ) }
515 | '$' Identifier
{ MyAtom
->new ( value
=> '$'.$item[2]->reprint() ) }
518 Array
: "[" "]" Array
{ MyAtom
->new ( value
=> '[]'.$item[3]->reprint() ) }
519 | "[" Expression
"]" Array
520 { MyAtom
->new ( value
=> '['.$item[2]->reprint().']'.$item[4]->reprint() ) }
521 | "[" Expression
"]" { MyAtom
->new ( value
=> '['.$item[2]->reprint().']' ) }
522 | "[" "]" { MyAtom
->new ( value
=> '[]' ) }
525 Identifier
: SimpleIdentifier
"->" Identifier
526 { MyAtom
->new ( value
=> $item[1]->reprint() ."->" .$item[3]->reprint() ) }
529 SimpleIdentifier
: /[a-zA-Z][a-zA-Z0-9_]*/ { MyAtom
->new ( value
=> $item[1] ) }
531 Numerical
: /[\d]+(\.[\d+])?/ { MyAtom
->new ( value
=> $item[1] ) }
533 String
: EmptyDQString
537 NotEmptyDQString
: /".*?[^\\\\]"/s { MyAtom
->new ( value
=> $item[1] ) }
538 EmptyDQString
: '""' { MyAtom
->new ( value
=> '""' ) }
539 NotEmptySQString
: /'.*?[^\\\\]'/s { MyAtom
->new ( value
=> $item[1] ) }
540 EmptySQString
: "''" { MyAtom
->new ( value
=> "''" ) }
544 my $parser = new Parse
::RecDescent
($grammar);
545 my $tree = $parser->Script($input);
547 print $tree->reprint();
552 # vim:set shiftwidth=4: