File Coverage

blib/lib/FFI/Platypus/TypeParser/Version1.pm
Criterion Covered Total %
statement 102 103 99.0
branch 74 76 97.3
condition 22 28 78.5
subroutine 10 10 100.0
pod 0 3 0.0
total 208 220 94.5


line stmt bran cond sub pod time code
1             package FFI::Platypus::TypeParser::Version1;
2              
3 37     37   11462 use strict;
  37         83  
  37         1482  
4 37     37   220 use warnings;
  37         69  
  37         2040  
5 37     37   798 use 5.008004;
  37         184  
6 37     37   292 use Carp qw( croak );
  37         74  
  37         3386  
7 37     37   291 use parent qw( FFI::Platypus::TypeParser );
  37         99  
  37         393  
8 37     37   2596 use constant _version => 1;
  37         72  
  37         36237  
9              
10             # ABSTRACT: FFI Type Parser Version One
11             our $VERSION = '2.11'; # VERSION
12              
13              
14             our @CARP_NOT = qw( FFI::Platypus FFI::Platypus::TypeParser );
15              
16             my %reserved = map { $_ => 1 } qw(
17             string
18             object
19             type
20             role
21             union
22             class
23             struct
24             record
25             array
26             senum
27             enum
28             );
29              
30             # The type parser is responsible for deciding if something is a legal
31             # alias name. Since this needs to be checked before the type is parsed
32             # it is separate from set_alias below.
33             sub check_alias
34             {
35 237     237 0 7205 my($self, $alias) = @_;
36 237 100       1321 croak "spaces not allowed in alias" if $alias =~ /\s/;
37 235 100       1572 croak "allowed characters for alias: [A-Za-z0-9_]" if $alias !~ /^[A-Za-z0-9_]+$/;
38             croak "reserved world \"$alias\" cannot be used as an alias"
39 233 100       1242 if $reserved{$alias};
40             croak "alias \"$alias\" conflicts with existing type"
41             if defined $self->type_map->{$alias}
42             || $self->types->{$alias}
43 229 100 100     667 || $self->global_types->{basic}->{$alias};
      100        
44 223         569 return 1;
45             }
46              
47             sub set_alias
48             {
49 225     225 0 526 my($self, $alias, $type) = @_;
50 225         552 $self->types->{$alias} = $type;
51             }
52              
53 37         57854 use constant type_regex =>
54              
55             qr/^ #
56             #
57             \s* # prefix white space
58             #
59             (?: #
60             #
61             \( ([^)]*) \) -> (.*) # closure, argument types $1, return type $2
62             | #
63             ( string | record ) \s* \( \s* ([0-9]+) \s* \) (?: \s* (\*) | ) # fixed record $3, fixed string $4, ponter $5
64             | #
65             record \s* \( ( \s* (?: [A-Za-z_] [A-Za-z_0-9]* :: )* [A-Za-z_] [A-Za-z_0-9]* ) \s* \) (?: \s* (\*) | ) # record class $6, pointer $7
66             | #
67             ( (?: [A-Za-z_] [A-Za-z_0-9]* \s+ )* [A-Za-z_] [A-Za-z_0-9]* ) \s* # unit type name $8
68             #
69             (?: (\*) | \[ ([0-9]*) \] | ) # pointer $9, array $10
70             | #
71             object \s* \( \s* ( (?: [A-Za-z_] [A-Za-z_0-9]* :: )* [A-Za-z_] [A-Za-z_0-9]* ) # object class $11
72             (?: \s*,\s* ( (?: [A-Za-z_] [A-Za-z_0-9]* \s+ )* [A-Za-z_] [A-Za-z_0-9]* ) )? # type $12
73             \s* \) #
74             ) #
75             #
76             \s* # trailing white space
77             #
78 37     37   299 $/x; #
  37         73  
79              
80             sub parse
81             {
82 2662     2662 0 86388 my($self, $name, $opt) = @_;
83              
84 2662   100     10081 $opt ||= {};
85              
86 2662 100       6223 return $self->types->{$name} if $self->types->{$name};
87              
88 1935 100       15130 $name =~ type_regex or croak "bad type name: $name";
89              
90 1926 100       5777 if(defined (my $at = $1)) # closure
91             {
92 54         154 my $rt = $2;
93             return $self->types->{$name} = $self->create_type_closure(
94             $self->abi,
95             $self->parse($rt, $opt),
96 54         281 map { $self->parse($_, $opt) } map { my $t = $_; $t =~ s/^\s+//; $t =~ s/\s+$//; $t } split /,/, $at,
  37         96  
  37         82  
  37         115  
  37         705  
  37         150  
97             );
98             }
99              
100 1872 100       4835 if(defined (my $size = $4)) # fixed record / fixed string
101             {
102 45 100       1980 croak "fixed record / fixed string size must be larger than 0"
103             unless $size > 0;
104              
105 33 100 100     161 if(my $pointer = $5)
    100 66        
106             {
107 19         147 return $self->types->{$name} = $self->create_type_record(
108             0,
109             $size,
110             );
111             }
112             elsif($opt->{member} || ($3 eq 'string' && $self->_version > 1))
113             {
114 7         45 return $self->types->{"$name *"} = $self->create_type_record(
115             0,
116             $size,
117             );
118             }
119             else
120             {
121 7 100       17 if($self->_version > 1)
122             {
123 1         158 croak "classless record not allowed as value type";
124             }
125             else
126             {
127 6         695 croak "fixed string / classless record not allowed as value type";
128             }
129             }
130             }
131              
132 1827 100       4120 if(defined (my $class = $6)) # class record
133             {
134 15   66     887 my $size_method = $class->can('ffi_record_size') || $class->can('_ffi_record_size') || croak "$class has no ffi_record_size or _ffi_record_size method";
135 11 100       54 if(my $pointer = $7)
136             {
137 5         37 return $self->types->{$name} = $self->create_type_record(
138             0,
139             $class->$size_method,
140             $class,
141             );
142             }
143             else
144             {
145 6         37 return $self->types->{$name} = $self->create_type_record(
146             1,
147             $class->$size_method,
148             $class,
149             $class->_ffi_meta->ptr,
150             );
151             }
152             }
153              
154 1812 100       4598 if(defined (my $unit_name = $8)) # basic type
155             {
156 1786 100       4486 if($self->global_types->{basic}->{$unit_name})
157             {
158 1590 100       3920 if(my $pointer = $9)
159             {
160 69 100       521 croak "void pointer not allowed" if $unit_name eq 'void';
161 67         179 return $self->types->{$name} = $self->global_types->{ptr}->{$unit_name};
162             }
163              
164 1521 100       3487 if(defined (my $size = $10)) # array
165             {
166 144 100       765 croak "void array not allowed" if $unit_name eq 'void';
167 142 100       401 if($size ne '')
168             {
169 55 100       560 croak "array size must be larger than 0" if $size < 1;
170             return $self->types->{$name} = $self->create_type_array(
171 53         169 $self->global_types->{basic}->{$unit_name}->type_code,
172             $size,
173             );
174             }
175             else
176             {
177             return $self->global_types->{array}->{$unit_name} ||= $self->create_type_array(
178 87   66     289 $self->global_types->{basic}->{$unit_name}->type_code,
179             0,
180             );
181             }
182             }
183              
184             # basic type with no decorations
185 1377         2866 return $self->global_types->{basic}->{$unit_name};
186             }
187              
188 196 100       554 if(my $map_name = $self->type_map->{$unit_name})
189             {
190 158 100       471 if(my $pointer = $9)
191             {
192 14         84 return $self->types->{$name} = $self->parse("$map_name *", $opt);
193             }
194 144 100       533 if(defined (my $size = $10))
195             {
196 19 100       39 if($size ne '')
197             {
198 11 100       362 croak "array size must be larger than 0" if $size < 1;
199 9         26 return $self->types->{$name} = $self->parse("$map_name [$size]", $opt);
200             }
201             else
202             {
203 8         22 return $self->types->{$name} = $self->parse("$map_name []", $opt);
204             }
205             }
206              
207 125         750 return $self->types->{$name} = $self->parse("$map_name", $opt);
208             }
209              
210 38 100       115 if(my $pointer = $9)
211             {
212 7         18 my $unit_type = $self->parse($unit_name, $opt);
213              
214 7 100       36 if($unit_type->is_record_value)
215             {
216 3         25 my $meta = $unit_type->meta;
217             return $self->types->{$name} = $self->create_type_record(
218             0,
219             $meta->{size},
220             $meta->{class},
221 3         23 );
222             }
223              
224 4         11 my $basic_name = $self->global_types->{rev}->{$unit_type->type_code};
225 4 100       10 if($basic_name)
226             {
227 2         28 return $self->types->{$name} = $self->parse("$basic_name *", $opt);
228             }
229             else
230             {
231 2         268 croak "cannot make a pointer to $unit_name";
232             }
233             }
234              
235 31 100       132 if(defined (my $size = $10))
236             {
237 18         121 my $unit_type = $self->parse($unit_name, $opt);
238 18         51 my $basic_name = $self->global_types->{rev}->{$unit_type->type_code};
239 18 100       55 if($basic_name)
240             {
241 14 100       40 if($size ne '')
242             {
243 2 50       9 croak "array size must be larger than 0" if $size < 1;
244 2         6 return $self->types->{$name} = $self->parse("$basic_name [$size]", $opt);
245             }
246             else
247             {
248 12         50 return $self->types->{$name} = $self->parse("$basic_name []", $opt);
249             }
250             }
251             else
252             {
253 4         496 croak "cannot make an array of $unit_name";
254             }
255             }
256              
257 13 100       92 if($name eq 'string ro')
    100          
258             {
259 4         12 return $self->global_types->{basic}->{string};
260             }
261             elsif($name eq 'string rw')
262             {
263 7   66     22 return $self->global_types->{v2}->{string_rw} ||= $self->create_type_string(1);
264             }
265              
266 2   33     11 return $self->types->{$name} || croak "unknown type: $unit_name";
267             }
268              
269 26 50       132 if(defined (my $class = $11)) # object type
270             {
271 26   100     113 my $basic_name = $12 || 'opaque';
272 26         89 my $basic_type = $self->parse($basic_name);
273 26 100       169 if($basic_type->is_object_ok)
274             {
275 24         334 return $self->types->{$name} = $self->create_type_object(
276             $basic_type->type_code,
277             $class,
278             );
279             }
280             else
281             {
282 2         301 croak "cannot make an object of $basic_name";
283             }
284             }
285              
286 0           croak "internal error parsing: $name";
287             }
288              
289             1;
290              
291             __END__