1package FFI::Platypus::TypeParser::Version0; 2 3use strict; 4use warnings; 5use 5.008004; 6use Carp qw( croak ); 7use parent qw( FFI::Platypus::TypeParser ); 8 9# ABSTRACT: FFI Type Parser Version Zero 10our $VERSION = '1.56'; # VERSION 11 12 13our @CARP_NOT = qw( FFI::Platypus FFI::Platypus::TypeParser ); 14 15# The type parser is responsible for deciding if something is a legal 16# alias name. Since this needs to be checked before the type is parsed 17# it is separate from set_alias below. 18sub check_alias 19{ 20 my($self, $alias) = @_; 21 croak "spaces not allowed in alias" if $alias =~ /\s/; 22 croak "allowed characters for alias: [A-Za-z0-9_]" if $alias !~ /^[A-Za-z0-9_]+$/; 23 croak "alias \"$alias\" conflicts with existing type" 24 if defined $self->type_map->{$alias} 25 || $self->types->{$alias}; 26 return 1; 27} 28 29sub set_alias 30{ 31 my($self, $alias, $type) = @_; 32 $self->types->{$alias} = $type; 33} 34 35# This method takes a string representation of the a type and 36# returns the internal platypus type representation. 37sub parse 38{ 39 my($self, $name) = @_; 40 41 return $self->types->{$name} if defined $self->types->{$name}; 42 43 # Darmock and Legacy Code at Tanagra 44 unless($name =~ /-\>/ || $name =~ /^record\s*\([0-9A-Z:a-z_]+\)$/ 45 || $name =~ /^string(_rw|_ro|\s+rw|\s+ro|\s*\([0-9]+\))$/) 46 { 47 my $basic = $name; 48 my $extra = ''; 49 if($basic =~ s/\s*((\*|\[|\<).*)$//) 50 { 51 $extra = " $1"; 52 } 53 if(defined $self->type_map->{$basic}) 54 { 55 my $new_name = $self->type_map->{$basic} . $extra; 56 if($new_name ne $name) 57 { 58 # hopefully no recursion here. 59 return $self->types->{$name} = $self->parse($new_name); 60 } 61 } 62 } 63 64 if($name =~ m/^ \( (.*) \) \s* -\> \s* (.*) \s* $/x) 65 { 66 my @argument_types = map { $self->parse($_) } map { my $t = $_; $t =~ s/^\s+//; $t =~ s/\s+$//; $t } split /,/, $1; 67 my $return_type = $self->parse($2); 68 return $self->types->{$name} = $self->create_type_closure($self->abi, $return_type, @argument_types); 69 } 70 71 if($name =~ /^ string \s* \( ([0-9]+) \) $/x) 72 { 73 return $self->types->{$name} = $self->create_type_record( 74 0, 75 $1, # size 76 ); 77 } 78 79 if($name =~ /^ string ( _rw | _ro | \s+ro | \s+rw | ) $/x) 80 { 81 return $self->types->{$name} = $self->create_type_string( 82 defined $1 && $1 =~ /rw/ ? 1 : 0, # rw 83 ); 84 } 85 86 if($name =~ /^ record \s* \( ([0-9]+) \) $/x) 87 { 88 return $self->types->{$name} = $self->create_type_record( 89 0, 90 $1, # size 91 ); 92 } 93 94 if($name =~ /^ record \s* \( ([0-9:A-Za-z_]+) \) $/x) 95 { 96 my $size; 97 my $classname = $1; 98 unless($classname->can('ffi_record_size') || $classname->can('_ffi_record_size')) 99 { 100 my $pm = "$classname.pm"; 101 $pm =~ s/\//::/g; 102 require $pm; 103 } 104 if($classname->can('ffi_record_size')) 105 { 106 $size = $classname->ffi_record_size; 107 } 108 elsif($classname->can('_ffi_record_size')) 109 { 110 $size = $classname->_ffi_record_size; 111 } 112 else 113 { 114 croak "$classname has not ffi_record_size or _ffi_record_size method"; 115 } 116 return $self->global_types->{record}->{$classname} ||= $self->create_type_record( 117 0, 118 $size, # size 119 $classname, # record_class 120 ); 121 } 122 123 # array types 124 if($name =~ /^([\S]+)\s+ \[ ([0-9]*) \] $/x) 125 { 126 my $size = $2 || ''; 127 my $basic = $self->global_types->{basic}->{$1} || croak("unknown ffi/platypus type $name [$size]"); 128 if($size) 129 { 130 return $self->types->{$name} = $self->create_type_array( 131 $basic->type_code, 132 $size, 133 ); 134 } 135 else 136 { 137 return $self->global_types->{array}->{$name} ||= $self->create_type_array( 138 $basic->type_code, 139 0 140 ); 141 } 142 } 143 144 # pointer types 145 if($name =~ s/\s+\*$//) 146 { 147 return $self->global_types->{ptr}->{$name} || croak("unknown ffi/platypus type $name *"); 148 } 149 150 # basic types 151 return $self->global_types->{basic}->{$name} || croak("unknown ffi/platypus type $name"); 152} 153 1541; 155 156__END__ 157 158=pod 159 160=encoding UTF-8 161 162=head1 NAME 163 164FFI::Platypus::TypeParser::Version0 - FFI Type Parser Version Zero 165 166=head1 VERSION 167 168version 1.56 169 170=head1 SYNOPSIS 171 172 use FFI::Platypus; 173 my $ffi = FFI::Platypus->new( api => 0 ); 174 $ffi->type('record(Foo::Bar)' => 'foo_bar_t'); 175 $ffi->type('opaque' => 'baz_t'); 176 $ffi->type('opaque*' => 'baz_ptr'); 177 178=head1 DESCRIPTION 179 180This documents the original L<FFI::Platypus> type parser. It was the default and only 181type parser used by L<FFI::Platypus> starting with version C<0.02>. Starting with 182version C<1.00> L<FFI::Platypus> comes with a new type parser with design fixes that 183are not backward compatibility. 184 185=head2 Interface differences 186 187=over 188 189=item Pass-by-value records are not allowed 190 191Originally L<FFI::Platypus> only supported passing records as a pointer. The type 192C<record(Foo::Bar)> actually passes a pointer to the record. In the version 1.00 parser 193allows C<record(Foo::Bar)> which is pass-by-value (the contents of the record is copied 194onto the stack) and C<record(Foo::Bar)*> which is pass-by-reference or pointer (a pointer 195to the record is passed to the callee so that it can make modifications to the record). 196 197TL;DR C<record(Foo::Bar)> in version 0 is equivalent to C<record(Foo::Bar)*> in the 198version 1 API. There is no equivalent to C<record(Foo::Bar)*> in the version 0 API. 199 200=item decorate aliases of basic types 201 202This is not allowed in the version 0 API: 203 204 $ffi->type('opaque' => 'foo_t'); # ok! 205 $ffi->type('foo_t*' => 'foo_ptr'); # not ok! in version 0, ok! in version 1 206 207Instead you need to use the basic type in the second type definition: 208 209 $ffi->type('opaque' => 'foo_t'); # ok! 210 $ffi->type('opaque*' => 'foo_ptr'); # ok! 211 212=item object types are not allowed 213 214 $ffi->type('object(Foo::Bar)'); # not ok! in version 0, ok! in version 1 215 216=back 217 218=head1 SEE ALSO 219 220=over 4 221 222=item L<FFI::Platypus> 223 224The core L<FFI::Platypus> documentation. 225 226=item L<FFI::Platypus::TypeParser::Version1> 227 228The API C<1.00> type parser. 229 230=back 231 232=head1 AUTHOR 233 234Author: Graham Ollis E<lt>plicease@cpan.orgE<gt> 235 236Contributors: 237 238Bakkiaraj Murugesan (bakkiaraj) 239 240Dylan Cali (calid) 241 242pipcet 243 244Zaki Mughal (zmughal) 245 246Fitz Elliott (felliott) 247 248Vickenty Fesunov (vyf) 249 250Gregor Herrmann (gregoa) 251 252Shlomi Fish (shlomif) 253 254Damyan Ivanov 255 256Ilya Pavlov (Ilya33) 257 258Petr Písař (ppisar) 259 260Mohammad S Anwar (MANWAR) 261 262Håkon Hægland (hakonhagland, HAKONH) 263 264Meredith (merrilymeredith, MHOWARD) 265 266Diab Jerius (DJERIUS) 267 268Eric Brine (IKEGAMI) 269 270szTheory 271 272José Joaquín Atria (JJATRIA) 273 274Pete Houston (openstrike, HOUSTON) 275 276=head1 COPYRIGHT AND LICENSE 277 278This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis. 279 280This is free software; you can redistribute it and/or modify it under 281the same terms as the Perl 5 programming language system itself. 282 283=cut 284