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