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   114 use strict;
  15         33  
  15         480  
3 15     15   83 use warnings;
  15         33  
  15         5654  
4              
5             our $VERSION = '0.11';
6              
7             sub grammar {
8 15     15 0 186 <<'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' function_pointer ';'
56             {
57             # a function-pointer typedef
58             Inline::Struct::grammar::ptr_register($thisparser, $item[2][1]);
59             }
60              
61             function_pointer: (/[^\s\(]+/)(s) '(' '*' IDENTIFIER ')' '(' (/[^\s\)]+/)(s) ')'
62             {
63             # (rettype, l, l, ident, l, l, args)
64             [join('',@{$item[1]}), $item[4], join('',@{$item[7]})]
65             }
66              
67             enum: 'enum' '{' (/[^\s\}]+/)(s) '}'
68             {
69             $item[3];
70             }
71              
72             fields: '{' field(s) '}' { [ grep ref, @{$item[2]} ] }
73              
74             field: comment
75             | type_identifier
76              
77             IDENTIFIER: /[~_a-z]\w*/i
78              
79             comment: m{\s* // [^\n]* \n }x
80             | m{\s* /\* (?:[^*]+|\*(?!/))* \*/ ([ \t]*)? }x
81              
82             type_identifier: TYPE(s) star(s?) IDENTIFIER(?) ';'
83             {
84             my ($identifier) = @{ $item[3] };
85             $identifier = pop @{$item[1]}
86             if !defined $identifier; # no stars = overgreedy
87             my $type = join ' ', @{$item[1]};
88             $type .= join '',' ',@{$item[2]} if @{$item[2]};
89             [ $type, $identifier ];
90             }
91             | enum IDENTIFIER ';'
92             {
93             [ 'IV', $item[2] ];
94             }
95             | function_pointer ';'
96             {
97             [ 'void *', $item[1][1] ];
98             }
99              
100             star: '*' | '&'
101              
102             TYPE: /\w+/
103              
104             ALL: /.*/
105              
106             END
107              
108             }
109              
110             # Adds an entry in these fields of the parser:
111             # ->{data}{typeconv}{input_expr}
112             # ->{data}{typeconv}{output_expr}
113             # ->{data}{typeconv}{valid_types}
114             # ->{data}{typeconv}{valid_rtypes}
115             # ->{data}{typeconv}{type_kind}
116             sub typemap {
117 19     19 0 187850 my $parser = shift;
118 19         58 my $perlname = shift;
119 19         41 my $cname = shift;
120 19         67 my $type = "O_OBJECT_$perlname";
121 19         91 $parser->{data}{typeconv}{input_expr}{$type} = <<'END';
122             if (!sv_isobject($arg)) {
123             warn ( \"$pname() -- $var is not a blessed reference\" );
124             XSRETURN_UNDEF;
125             }
126             $var = ($type)SvIV((SV*)SvRV( $arg ));
127             if (!$var) {
128             warn ( \"$pname() -- $var is null pointer\" );
129             XSRETURN_UNDEF;
130             }
131             END
132 19         147 $parser->{data}{typeconv}{output_expr}{$type} = <
133             {
134             HV *map = get_hv("Inline::Struct::${perlname}::_map_", 1);
135             SV *lookup = newSViv((IV)\$var);
136             STRLEN klen;
137             char *key = SvPV(lookup, klen);
138             sv_2mortal(lookup);
139             if (hv_exists(map, key, klen)) {
140             HV *info = (HV*)SvRV(*hv_fetch(map, key, klen, 0));
141             SV *refcnt = *hv_fetch(info, "REFCNT", 6, 0);
142             sv_inc(refcnt);
143             }
144             else {
145             HV *info = newHV();
146             SV *info_ref = newRV((SV*)info);
147             hv_store(info, "REFCNT", 6, newSViv(1), 0);
148             hv_store(info, "FREE", 4, newSViv(0), 0);
149             hv_store(map, key, klen, info_ref, 0);
150             }
151             }
152             sv_setref_pv( \$arg, "Inline::Struct::$perlname", (void*)\$var );
153             END
154 19         94 _register_type($parser, $cname." *", $type);
155             }
156              
157             sub _register_type {
158 28     28   2754 my ($parser, $cname, $type) = @_;
159 28         187 $parser->{data}{typeconv}{$_}{$cname}++ for qw(valid_types valid_rtypes);
160 28         674 $parser->{data}{typeconv}{type_kind}{$cname} = $type;
161             }
162              
163             sub alias {
164 7     7 0 19303 my ($parser, $type, $alias) = @_;
165 7         22 $type .= " *"; $alias .= " *"; # because I only deal with pointers.
  7         14  
166 7   50     50 _register_type($parser, $alias, $parser->{data}{typeconv}{type_kind}{$type} ||= {});
167             }
168              
169 1     1 0 4764 sub ptr_register { _register_type(@_, 'T_PTR') }
170              
171             1;