-
Notifications
You must be signed in to change notification settings - Fork 138
/
c_parens.t
139 lines (111 loc) · 4.3 KB
/
c_parens.t
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
#! perl
# Copyright (C) 2006-2014, Parrot Foundation.
use strict;
use warnings;
use lib qw( . lib ../lib ../../lib );
use Test::More tests => 3;
use Parrot::Distribution;
use Pod::Simple;
=head1 NAME
t/codingstd/c_parens.t - checks for rules related to parentheses in C source
=head1 SYNOPSIS
# test all files
% prove t/codingstd/c_parens.t
# test specific files
% perl t/codingstd/c_parens.t src/foo.c include/parrot/bar.h
=head1 DESCRIPTION
Checks that all C language source files have the proper use of parentheses,
as specified in PDD07.
=head1 SEE ALSO
L<docs/pdds/pdd07_codingstd.pod>
=cut
my $keywords = join '|' => sort { length $a <=> length $b } qw/
auto double int struct INTVAL
break else long switch UINTVAL
case enum register typedef FLOATVAL
char extern return union PIOOFF_T
const float short unsigned
continue for signed void
default goto sizeof volatile opcode_t
do if static while size_t
/;
my $DIST = Parrot::Distribution->new;
my @files = @ARGV ? <@ARGV> : $DIST->get_c_language_files();
check_parens(@files);
exit;
sub strip_pod {
my $buf = shift;
my $parser = Pod::Simple->new();
my $non_pod_buf;
$parser->output_string( \$non_pod_buf );
# set up a code handler to get at the non-pod
# thanks to Thomas Klausner's Pod::Strip for the inspiration
$parser->code_handler(
sub {
print {$_[2]{output_fh}} $_[0], "\n";
});
$parser->parse_string_document( $buf );
return $non_pod_buf;
}
sub check_parens {
my @keyword_paren;
my @non_keyword_paren;
my @space_between_parens;
foreach my $file (@_) {
my $path = @ARGV ? $file : $file->path();
my $buf = $DIST->slurp($path);
# only strip pod from .ops files
if ( $path =~ m/\.ops$/ ) {
$buf = strip_pod($buf);
}
# strip ', ", and C comments
$buf =~ s{ (?:
(?: (') (?: \\\\ | \\' | [^'] )* (') ) # remove ' string
| (?: (") (?: \\\\ | \\" | [^"] )* (") ) # remove " string
| /(\*) .*? (\*)/ # remove C comment
)
}{defined $1 ? "$1$2" : defined $3 ? "$3$4" : "$5$6"}egsx;
my @lines = split( /\n/, $buf );
for my $line (@lines) {
# skip #defines and typedefs
next if $line =~ m{(?:(#\s*define|^\s*typedef))};
if ( $line =~ m{ ( (?<!\w) (?:$keywords) (?: \( ) ) }xo ) {
my $paren = $1;
# ops use the same names as some C keywords, so skip
next if $line =~ m{^op};
push @keyword_paren => "$path: $paren";
}
if ( $line =~ m{ ( (?<!\w) (?!(?:$keywords)\W) \w+ \s+ \( ) }xo ) {
# Misparse the gperf list as function calls, so skip them.
# The generated C is checked
next if $path =~ m{src/string/namealias_c\.in};
push @non_keyword_paren => "$path: $1";
}
if ( $line =~ m{ ( \( [ \t]+ [^\n] | [^\n] [ \t]+ \) ) }x ) {
push @space_between_parens => "$path: $1";
}
}
}
## L<PDD07/Code Formatting/"there should be at least one space between a C keyword and any subsequent open parenthesis">
is( join("\n",@keyword_paren), "", <<END_DESCRIPTION);
there should be at least one space between a C
keyword and any subsequent open parenthesis
END_DESCRIPTION
## L<PDD07/Code Formatting/"There should be no space between a function name and the following open parenthesis">
is( join("\n",@non_keyword_paren), "", <<END_DESCRIPTION);
There should be no space between a function name
and the following open parenthesis
END_DESCRIPTION
## L<PDD07/Code Formatting/"parentheses should not have space immediately after the opening parenthesis nor immediately before the closing parenthesis">
is( join("\n",@space_between_parens), "", <<END_DESCRIPTION);
parentheses should not have space immediately
after the opening parenthesis nor immediately
before the closing parenthesis
END_DESCRIPTION
}
# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4: