| line | stmt | bran | cond | sub | pod | time | code | 
| 1 | 8 |  |  | 8 |  | 13329 | use strict; use warnings; | 
|  | 8 |  |  | 8 |  | 25 |  | 
|  | 8 |  |  |  |  | 235 |  | 
|  | 8 |  |  |  |  | 43 |  | 
|  | 8 |  |  |  |  | 25 |  | 
|  | 8 |  |  |  |  | 292 |  | 
| 2 |  |  |  |  |  |  | package Inline::C::Parser::RegExp; | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 8 |  |  | 8 |  | 45 | use Carp; | 
|  | 8 |  |  |  |  | 15 |  | 
|  | 8 |  |  |  |  | 7408 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | sub register { | 
| 7 |  |  |  |  |  |  | { | 
| 8 | 8 |  |  | 8 | 0 | 7862 | extends => [qw(C)], | 
| 9 |  |  |  |  |  |  | overrides => [qw(get_parser)], | 
| 10 |  |  |  |  |  |  | } | 
| 11 |  |  |  |  |  |  | } | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | sub get_parser { | 
| 14 | 8 | 100 |  | 8 | 0 | 53 | Inline::C::_parser_test($_[0]->{CONFIG}{DIRECTORY}, "Inline::C::Parser::RegExp::get_parser called\n") if $_[0]->{CONFIG}{_TESTING}; | 
| 15 | 8 |  |  |  |  | 58 | bless {}, 'Inline::C::Parser::RegExp' | 
| 16 |  |  |  |  |  |  | } | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | sub code { | 
| 19 | 8 |  |  | 8 | 0 | 17 | my ($self,$code) = @_; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | # These regular expressions were derived from Regexp::Common v0.01. | 
| 22 | 8 |  |  |  |  | 13 | my $RE_comment_C = q{(?:(?:\/\*)(?:(?:(?!\*\/)[\s\S])*)(?:\*\/))}; | 
| 23 | 8 |  |  |  |  | 24 | my $RE_comment_Cpp = q{(?:\/\*(?:(?!\*\/)[\s\S])*\*\/|\/\/[^\n]*\n)}; | 
| 24 | 8 |  |  |  |  | 15 | my $RE_quoted = ( | 
| 25 |  |  |  |  |  |  | q{(?:(?:\")(?:[^\\\"]*(?:\\.[^\\\"]*)*)(?:\")} | 
| 26 |  |  |  |  |  |  | . q{|(?:\')(?:[^\\\']*(?:\\.[^\\\']*)*)(?:\'))} | 
| 27 |  |  |  |  |  |  | ); | 
| 28 | 8 |  |  |  |  | 16 | our $RE_balanced_brackets; $RE_balanced_brackets = | 
| 29 | 8 |  |  |  |  | 65 | qr'(?:[{]((?:(?>[^{}]+)|(??{$RE_balanced_brackets}))*)[}])'; | 
| 30 | 8 |  |  |  |  | 15 | our $RE_balanced_parens; $RE_balanced_parens   = | 
| 31 | 8 |  |  |  |  | 44 | qr'(?:[(]((?:(?>[^()]+)|(??{$RE_balanced_parens}))*)[)])'; | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | # First, we crush out anything potentially confusing. | 
| 34 |  |  |  |  |  |  | # The order of these _does_ matter. | 
| 35 | 8 |  |  |  |  | 154 | $code =~ s/$RE_comment_C/ /go; | 
| 36 | 8 |  |  |  |  | 184 | $code =~ s/$RE_comment_Cpp/ /go; | 
| 37 | 8 |  |  |  |  | 19 | $code =~ s/^\#.*(\\\n.*)*//mgo; | 
| 38 |  |  |  |  |  |  | #$code =~ s/$RE_quoted/\"\"/go; # Buggy, if included. | 
| 39 | 8 |  |  |  |  | 73 | $code =~ s/$RE_balanced_brackets/{ }/go; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 8 |  |  |  |  | 24 | $self->{_the_code_most_recently_parsed} = $code; # Simplifies debugging. | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | my $normalize_type = sub { | 
| 44 |  |  |  |  |  |  | # Normalize a type for lookup in a typemap. | 
| 45 | 66 |  |  | 66 |  | 87 | my($type) = @_; | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | # Remove "extern". | 
| 48 |  |  |  |  |  |  | # But keep "static", "inline", "typedef", etc, | 
| 49 |  |  |  |  |  |  | #  to cause desirable typemap misses. | 
| 50 | 66 |  |  |  |  | 82 | $type =~ s/\bextern\b//g; | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | # Whitespace: only single spaces, none leading or trailing. | 
| 53 | 66 |  |  |  |  | 165 | $type =~ s/\s+/ /g; | 
| 54 | 66 |  |  |  |  | 111 | $type =~ s/^\s//; $type =~ s/\s$//; | 
|  | 66 |  |  |  |  | 125 |  | 
| 55 |  |  |  |  |  |  |  | 
| 56 |  |  |  |  |  |  | # Adjacent "derivative characters" are not separated by whitespace, | 
| 57 |  |  |  |  |  |  | # but _are_ separated from the adjoining text. | 
| 58 |  |  |  |  |  |  | # [ Is really only * (and not ()[]) needed??? ] | 
| 59 | 66 |  |  |  |  | 91 | $type =~ s/\*\s\*/\*\*/g; | 
| 60 | 66 |  |  |  |  | 88 | $type =~ s/(?<=[^ \*])\*/ \*/g; | 
| 61 |  |  |  |  |  |  |  | 
| 62 | 66 |  |  |  |  | 112 | return $type; | 
| 63 | 8 |  |  |  |  | 43 | }; | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | # The decision of what is an acceptable declaration was originally | 
| 66 |  |  |  |  |  |  | # derived from Inline::C::grammar.pm version 0.30 (Inline 0.43). | 
| 67 |  |  |  |  |  |  |  | 
| 68 | 8 |  |  |  |  | 26 | my $re_plausible_place_to_begin_a_declaration = qr { | 
| 69 |  |  |  |  |  |  | # The beginning of a line, possibly indented. | 
| 70 |  |  |  |  |  |  | # (Accepting indentation allows for C code to be aligned with | 
| 71 |  |  |  |  |  |  | #  its surrounding perl, and for backwards compatibility with | 
| 72 |  |  |  |  |  |  | #  Inline 0.43). | 
| 73 |  |  |  |  |  |  | (?m: ^ ) \s* | 
| 74 |  |  |  |  |  |  | }xo; | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | # Instead of using \s , we don't tolerate blank lines. | 
| 77 |  |  |  |  |  |  | # This matches user expectation better than allowing arbitrary | 
| 78 |  |  |  |  |  |  | # vertical whitespace. | 
| 79 | 8 |  |  |  |  | 20 | my $sp = qr{[ \t]|\n(?![ \t]*\n)}; | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 8 |  |  |  |  | 190 | my $re_type = qr{ | 
| 82 |  |  |  |  |  |  | ( | 
| 83 |  |  |  |  |  |  | (?: \w+ $sp* )+? # words | 
| 84 |  |  |  |  |  |  | (?: \*  $sp* )*  # stars | 
| 85 |  |  |  |  |  |  | ) | 
| 86 |  |  |  |  |  |  | }xo; | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 8 |  |  |  |  | 111 | my $re_identifier = qr{ (\w+) $sp* }xo; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 8 |  |  |  |  | 32 | $code =~ s/\bconst\b//g; # Remove "const" qualifier - it's not wanted here. | 
| 91 |  |  |  |  |  |  |  | 
| 92 | 8 |  |  |  |  | 1353 | while ($code =~ m{ | 
| 93 |  |  |  |  |  |  | $re_plausible_place_to_begin_a_declaration | 
| 94 |  |  |  |  |  |  | ( $re_type $re_identifier $RE_balanced_parens $sp* (\;|\{) ) | 
| 95 |  |  |  |  |  |  | }xgo | 
| 96 |  |  |  |  |  |  | ) { | 
| 97 | 34 |  |  |  |  | 198 | my ($type, $identifier, $args, $what) = ($2,$3,$4,$5); | 
| 98 | 34 | 50 |  |  |  | 95 | $args = "" if $args =~ /^\s+$/; | 
| 99 |  |  |  |  |  |  |  | 
| 100 | 34 |  |  |  |  | 63 | my $is_decl     = $what eq ';'; | 
| 101 | 34 |  |  |  |  | 44 | my $function    = $identifier; | 
| 102 | 34 |  |  |  |  | 57 | my $return_type = &$normalize_type($type); | 
| 103 | 34 |  |  |  |  | 73 | my @arguments   = split ',', $args; | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 34 | 50 | 33 |  |  | 70 | goto RESYNC if $is_decl && !$self->{data}{AUTOWRAP}; | 
| 106 | 34 | 50 |  |  |  | 79 | goto RESYNC if $self->{data}{done}{$function}; | 
| 107 |  |  |  |  |  |  | goto RESYNC if !defined | 
| 108 | 34 | 50 |  |  |  | 72 | $self->{data}{typeconv}{valid_rtypes}{$return_type}; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 34 |  |  |  |  | 45 | my(@arg_names,@arg_types); | 
| 111 | 34 |  |  |  |  | 44 | my $dummy_name = 'arg1'; | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 34 |  |  |  |  | 51 | foreach my $arg (@arguments) { | 
| 114 | 32 |  |  |  |  | 39 | my $arg_no_space = $arg; | 
| 115 | 32 |  |  |  |  | 81 | $arg_no_space =~ s/\s//g; | 
| 116 |  |  |  |  |  |  | # If $arg_no_space is 'void', there will be no identifier. | 
| 117 | 32 | 50 |  |  |  | 620 | if (my($type, $identifier) = | 
|  |  | 0 |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | $arg =~ /^\s*$re_type(?:$re_identifier)?\s*$/o | 
| 119 |  |  |  |  |  |  | ) { | 
| 120 | 32 |  |  |  |  | 54 | my $arg_name = $identifier; | 
| 121 | 32 |  |  |  |  | 45 | my $arg_type = &$normalize_type($type); | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 32 | 50 | 66 |  |  | 77 | if ((!defined $arg_name) && ($arg_no_space ne 'void')) { | 
| 124 | 0 | 0 |  |  |  | 0 | goto RESYNC if !$is_decl; | 
| 125 | 0 |  |  |  |  | 0 | $arg_name = $dummy_name++; | 
| 126 |  |  |  |  |  |  | } | 
| 127 |  |  |  |  |  |  | goto RESYNC if ((!defined | 
| 128 | 32 | 50 | 66 |  |  | 117 | $self->{data}{typeconv}{valid_types}{$arg_type}) && ($arg_no_space ne 'void')); | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | # Push $arg_name onto @arg_names iff it's defined. Otherwise ($arg_no_space | 
| 131 |  |  |  |  |  |  | # was 'void'), push the empty string onto @arg_names (to avoid uninitialized | 
| 132 |  |  |  |  |  |  | # warnings emanating from C.pm). | 
| 133 | 32 | 100 |  |  |  | 68 | defined($arg_name) ? push(@arg_names,$arg_name) | 
| 134 |  |  |  |  |  |  | : push(@arg_names, ''); | 
| 135 | 32 | 100 |  |  |  | 42 | if ($arg_name) {push(@arg_types,$arg_type)} | 
|  | 22 |  |  |  |  | 41 |  | 
| 136 | 10 |  |  |  |  | 21 | else {push(@arg_types,'')} # $arg_no_space was 'void' - this push() avoids 'uninitialized' warnings from C.pm | 
| 137 |  |  |  |  |  |  | } | 
| 138 |  |  |  |  |  |  | elsif ($arg =~ /^\s*\.\.\.\s*$/) { | 
| 139 | 0 |  |  |  |  | 0 | push(@arg_names,'...'); | 
| 140 | 0 |  |  |  |  | 0 | push(@arg_types,'...'); | 
| 141 |  |  |  |  |  |  | } | 
| 142 |  |  |  |  |  |  | else { | 
| 143 | 0 |  |  |  |  | 0 | goto RESYNC; | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | # Commit. | 
| 148 | 34 |  |  |  |  | 40 | push @{$self->{data}{functions}}, $function; | 
|  | 34 |  |  |  |  | 71 |  | 
| 149 | 34 |  |  |  |  | 112 | $self->{data}{function}{$function}{return_type}= $return_type; | 
| 150 | 34 |  |  |  |  | 69 | $self->{data}{function}{$function}{arg_names} = [@arg_names]; | 
| 151 | 34 |  |  |  |  | 64 | $self->{data}{function}{$function}{arg_types} = [@arg_types]; | 
| 152 | 34 |  |  |  |  | 53 | $self->{data}{done}{$function} = 1; | 
| 153 |  |  |  |  |  |  |  | 
| 154 | 34 |  |  |  |  | 171 | next; | 
| 155 |  |  |  |  |  |  |  | 
| 156 | 0 |  |  |  |  | 0 | RESYNC:  # Skip the rest of the current line, and continue. | 
| 157 |  |  |  |  |  |  | $code =~ /\G[^\n]*\n/gc; | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  |  | 
| 160 | 8 |  |  |  |  | 86 | return 1;  # We never fail. | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | 1; |