File Coverage

blib/lib/Inline/Struct/grammar.pm
Criterion Covered Total %
statement 22 22 100.0
branch n/a
condition 1 2 50.0
subroutine 7 7 100.0
pod 0 4 0.0
total 30 35 85.7


line stmt bran cond sub pod time code
1             package Inline::Struct::grammar;
2 15     15   109 use strict;
  15         40  
  15         512  
3 15     15   89 use warnings;
  15         38  
  15         5914  
4              
5             our $VERSION = '0.11';
6              
7             sub grammar {
8 15     15 0 115 <<'END';
9              
10             code: part(s) {1}
11              
12             part: comment
13             | struct
14             {
15             my ($perlname, $cname, $fields) = @{$item[1]};
16             my @fields = map @$_, @$fields;
17             push @{$thisparser->{data}{structs}}, $perlname;
18             $thisparser->{data}{struct}{$perlname}{cname} = $cname;
19             $thisparser->{data}{struct}{$perlname}{field} = {reverse @fields};
20             $thisparser->{data}{struct}{$perlname}{fields} =
21             [ grep defined $thisparser->{data}{struct}{$perlname}{field}{$_},
22             @fields ];
23             Inline::Struct::grammar::typemap($thisparser, $perlname, $cname);
24             }
25             | typedef
26             | ALL
27              
28             struct: struct_identifier_fields
29             | 'typedef' 'struct' fields IDENTIFIER ';'
30             {
31             # [perlname, cname, fields]
32             [@item[4,4,3]]
33             }
34             | 'typedef' struct_identifier_fields IDENTIFIER ';'
35             {
36             Inline::Struct::grammar::alias($thisparser, $item[2][1], $item[3]);
37             $item[2]
38             }
39              
40             struct_identifier_fields:
41             'struct' IDENTIFIER fields ';'
42             {
43             # [perlname, cname, fields]
44             [$item[2], "@item[1,2]", $item[3]]
45             }
46              
47             typedef: 'typedef' 'struct' IDENTIFIER IDENTIFIER ';'
48             {
49             Inline::Struct::grammar::alias($thisparser, "@item[2,3]", $item[4]);
50             }
51             | 'typedef' enum IDENTIFIER ';'
52             {
53             Inline::Struct::grammar::_register_type($thisparser, $item[3], "T_IV");
54             }
55             | 'typedef' enum_label IDENTIFIER ';'
56             {
57             Inline::Struct::grammar::_register_type($thisparser, $item[3], "T_IV");
58             }
59             | 'typedef' function_pointer ';'
60             {
61             # a function-pointer typedef
62             Inline::Struct::grammar::ptr_register($thisparser, $item[2][1]);
63             }
64              
65             function_pointer: (/[^\s\(]+/)(s) '(' '*' IDENTIFIER ')' '(' (/[^\s\)]+/)(s) ')'
66             {
67             # (rettype, l, l, ident, l, l, args)
68             [join('',@{$item[1]}), $item[4], join('',@{$item[7]})]
69             }
70              
71             enum_list: '{' (/[^\s\}]+/)(s) '}'
72             { $item[2] }
73              
74             enum: 'enum' enum_list
75             { $item[2] }
76              
77             enum_label: 'enum' IDENTIFIER enum_list
78             { [ @item[1,2] ] }
79              
80             fields: '{' field(s) '}' { [ grep ref, @{$item[2]} ] }
81              
82             field: comment
83             | type_identifier
84              
85             IDENTIFIER: /[~_a-z]\w*/i
86              
87             comment: m{\s* // [^\n]* \n }x
88             | m{\s* /\* (?:[^*]+|\*(?!/))* \*/ ([ \t]*)? }x
89              
90             type_identifier:
91             'enum' IDENTIFIER IDENTIFIER ';'
92             {
93             [ 'IV', $item[3] ];
94             }
95             | TYPE(s) star(s?) IDENTIFIER(?) ';'
96             {
97             my ($identifier) = @{ $item[3] };
98             $identifier = pop @{$item[1]}
99             if !defined $identifier; # no stars = overgreedy
100             my $type = join ' ', @{$item[1]};
101             $type .= join '',' ',@{$item[2]} if @{$item[2]};
102             [ $type, $identifier ];
103             }
104             | enum IDENTIFIER ';'
105             {
106             [ 'IV', $item[2] ];
107             }
108             | function_pointer ';'
109             {
110             [ 'void *', $item[1][1] ];
111             }
112              
113             star: '*' | '&'
114              
115             TYPE: /\w+/
116              
117             ALL: /.*/
118              
119             END
120              
121             }
122              
123             # Adds an entry in these fields of the parser:
124             # ->{data}{typeconv}{input_expr}
125             # ->{data}{typeconv}{output_expr}
126             # ->{data}{typeconv}{valid_types}
127             # ->{data}{typeconv}{valid_rtypes}
128             # ->{data}{typeconv}{type_kind}
129             sub typemap {
130 21     21 0 233166 my $parser = shift;
131 21         64 my $perlname = shift;
132 21         60 my $cname = shift;
133 21         87 my $type = "O_OBJECT_$perlname";
134 21         117 $parser->{data}{typeconv}{input_expr}{$type} = <<'END';
135             if (!sv_isobject($arg)) {
136             warn ( \"$pname() -- $var is not a blessed reference\" );
137             XSRETURN_UNDEF;
138             }
139             $var = ($type)SvIV((SV*)SvRV( $arg ));
140             if (!$var) {
141             warn ( \"$pname() -- $var is null pointer\" );
142             XSRETURN_UNDEF;
143             }
144             END
145 21         239 $parser->{data}{typeconv}{output_expr}{$type} = <
146             {
147             HV *map = get_hv("Inline::Struct::${perlname}::_map_", 1);
148             SV *lookup = newSViv((IV)\$var);
149             STRLEN klen;
150             char *key = SvPV(lookup, klen);
151             sv_2mortal(lookup);
152             if (hv_exists(map, key, klen)) {
153             HV *info = (HV*)SvRV(*hv_fetch(map, key, klen, 0));
154             SV *refcnt = *hv_fetch(info, "REFCNT", 6, 0);
155             sv_inc(refcnt);
156             }
157             else {
158             HV *info = newHV();
159             SV *info_ref = newRV((SV*)info);
160             hv_store(info, "REFCNT", 6, newSViv(1), 0);
161             hv_store(info, "FREE", 4, newSViv(0), 0);
162             hv_store(map, key, klen, info_ref, 0);
163             }
164             }
165             sv_setref_pv( \$arg, "Inline::Struct::$perlname", (void*)\$var );
166             END
167 21         127 _register_type($parser, $cname." *", $type);
168             }
169              
170             sub _register_type {
171 31     31   7351 my ($parser, $cname, $type) = @_;
172 31         252 $parser->{data}{typeconv}{$_}{$cname}++ for qw(valid_types valid_rtypes);
173 31         801 $parser->{data}{typeconv}{type_kind}{$cname} = $type;
174             }
175              
176             sub alias {
177 7     7 0 18453 my ($parser, $type, $alias) = @_;
178 7         21 $type .= " *"; $alias .= " *"; # because I only deal with pointers.
  7         17  
179 7   50     52 _register_type($parser, $alias, $parser->{data}{typeconv}{type_kind}{$type} ||= {});
180             }
181              
182 1     1 0 4602 sub ptr_register { _register_type(@_, 'T_PTR') }
183              
184             1;