summaryrefslogtreecommitdiffstats
path: root/src/perl_checker.html.pl
blob: e90d2eba9eaea9e6f68e8c98689f57f564147940 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
$s = <<'EOF';
<head><title>perl_checker</title></head>
<h1>Goals of perl_checker</h1>

<ul>
<li> for beginners in perl:
  based on what the programmer is writing,
 <ul>
  <li> suggest better or more standard ways to do the same
  <li> detect wrong code
  <br>
  =&gt; a kind of automatic teacher
 </ul>

<li> for senior programmers:
  detect typos, unused variables, check number
  of parameters, global analysis to check method calls...

<li> enforce the same perl style by enforcing a subset of perl of features.
     In perl <a href="http://c2.com/cgi/wiki?ThereIsMoreThanOneWayToDoIt">There is more than one way to do it</a>. 
     In perl_checker's subset of Perl, there is not too many ways to do it.
     This is especially useful for big projects.
     (NB: the subset is chosen to keep a good expressivity)
</ul>

<h1>Compared to <a href="http://perlcritic.tigris.org/">Perl-Critic</a>

<ul>
<li>perl_checker use its own OCaml-written perl parser, which is in no way as robust as <a href="http://www.perl.com/pub/a/2005/06/09/ppi.html">PPI</a>.
    A PPI require is to be able to parse non finished perl documents.
    perl_checker is a checker, and it is not a big deal to die horribly on a weird perl expression, telling the programmer what to write instead.

<li>perl_checker is <b>much</b> faster (more than 100 times) (ML pattern matching rulez)

<li>perl_checker checks a lot more things than perlcritic: undeclared variables, unknown functions, unknown methods...

<li>and of course perl_checker checks are different from the Conways's <a href="http://www.oreilly.com/catalog/perlbp/">Perl Best Practices</a>
</ul>

<h1>Get it</h1>

<a href="http://cvs.mandriva.com/cgi-bin/cvsweb.cgi/soft/perl-MDK-Common/perl_checker.src/">CVS source</a>

<h1>Implemented features</h1>

<dl>
 <dt>white space normalization
 <dd>enforce a similar coding style. In many languages you can find a coding
 style document (eg: <a href="http://www.gnu.org/prep/standards_23.html">the GNU one</a>).

 TESTS=force_layout.t

 </dd>
 <dt>disallow <i>complex</i> expressions
 <dd>perl_checker try to ban some weird-not-used-a-lot features.

 TESTS=syntax_restrictions.t

 </dd>
 <dt>suggest simpler expressions
 <dd>when there is a simpler way to write an expression, suggest it. It can
 also help detecting errors.

 TESTS=suggest_better.t

 </dd>
 <dt>context checks
 <dd>Perl has types associated with variables names, the so-called "context".
 Some expressions mixing contexts are stupid, perl_checker detects them.

 TESTS=context.t

 </dd>
 <dt>function call check
 <dd>detection of unknown functions or mismatching prototypes (warning: since
  perl is a dynamic language, some spurious warnings may occur when a function
  is defined using stashes).

 TESTS=prototype.t

 </dd>
 <dt>method call check
 <dd>detection of unknown methods or mismatching prototypes. perl_checker
 doesn't have any idea what the object type is, it simply checks if a method
 with that name and that number of parameters exists.

 TESTS=method.t

 </dd>
 <dt>return value check
 <dd>dropping the result of a functionnally <i>pure</i> function is stupid.
 using the result of a function returning void is stupid too.

 TESTS=return_value.t

 </dd>
 <dt>detect some Perl traps
 <dd>some Perl expressions are stupid, and one gets a warning when running
 them with <tt>perl -w</tt>. The drawback are <tt>perl -w</tt> is the lack of
 code coverage, it only detects expressions which are evaluated.

 TESTS=various_errors.t

</dl>

<h1>Todo</h1>

Functionalities that would be nice:
<ul>
 <li> add flow analysis
 <li> maybe a "soft typing" type analysis
 <li> detect places where imperative code can be replaced with
   functional code (already done for some <b>simple</b> loops)
 <li> check the number of returned values when checking prototype compliance
</ul>
EOF

my $_rationale = <<'EOF';
<h1>Rationale</h1>

Perl is a big language, there is <a
href="http://c2.com/cgi/wiki?ThereIsMoreThanOneWayToDoIt">ThereIsMoreThanOneWayToDoIt</a>.
It has advantages but also some drawbacks for team project:
<ul>
 <li> it is hard to learn every special rules. Automatically enforced syntax
 coding rules help learning incrementally
EOF

use lib ('test', '..');
use read_t;
sub get_example {
    my ($file) = @_;
    my @tests = read_t::read_t("test/$file");
    $file =~ s|test/||;
    qq(<p><a name="$file"><table border=1 cellpadding=3>\n) .
      join('', map { 
	  my $lines = join("<br>", map { "<tt>" . html_quote($_) . "</tt>" } @{$_->{lines}});
	  my $logs = join("<br>", map { html_quote($_) } @{$_->{logs}});
	  "  <tr><td>\n", $lines, "</td><td>", $logs, "</td></tr>\n";
      } @tests) .
      "</table></a>\n";
}

sub anchor_to_examples {
    my ($s) = @_;
    $s =~ s!TESTS=(\S+)!(<a href="#$1">examples</a>)!g;
    $s;
}
sub fill_in_examples {
    my ($s) = @_;
    $s =~ s!TESTS=(\S+)!get_example($1)!ge;
    $s;
}

$s =~ s!<h1>Implemented features</h1>(.*)<h1>!
        "<h1>Implemented features</h1>" . anchor_to_examples($1) .
        "<h1>Examples</h1>" . fill_in_examples($1) .
        "<h1>"!se;

print $s;

sub html_quote {
    local $_ = $_[0];
    s/</&lt;/g;
    s/>/&gt;/g;
    s/^(\s*)/"&nbsp;" x length($1)/e;
    $_;
}