File Coverage

blib/lib/Tangence/Compiler/Parser.pm
Criterion Covered Total %
statement 149 150 99.3
branch 24 36 66.6
condition 3 3 100.0
subroutine 32 32 100.0
pod 8 15 53.3
total 216 236 91.5


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2011-2022 -- leonerd@leonerd.org.uk
5              
6 13     13   54816 use v5.26;
  13         45  
7 13     13   489 use Object::Pad 0.57;
  13         8470  
  13         63  
8              
9             package Tangence::Compiler::Parser 0.29;
10 13     13   7405 class Tangence::Compiler::Parser :isa(Parser::MGC);
  13         89697  
  13         504  
11              
12 13     13   6793 use Syntax::Keyword::Dynamically;
  13         7483  
  13         62  
13 13     13   973 use Syntax::Keyword::Match;
  13         651  
  13         64  
14              
15 13     13   666 use File::Basename qw( dirname );
  13         28  
  13         854  
16              
17 13     13   1586 use Tangence::Constants;
  13         44  
  13         3288  
18              
19             # Parsing is simpler if we treat Package.Name as a simple identifier
20 13     13   79 use constant pattern_ident => qr/[[:alnum:]_][\w.]*/;
  13         24  
  13         903  
21              
22 13     13   67 use constant pattern_comment => qr/#.*\n/;
  13         20  
  13         42465  
23              
24             =head1 NAME
25              
26             C - parse C interface definition files
27              
28             =head1 DESCRIPTION
29              
30             This subclass of L parses a L interface definition and
31             returns a metadata tree.
32              
33             =cut
34              
35             =head1 GRAMMAR
36              
37             The top level of an interface definition file contains C directives
38             and C and C definitions.
39              
40             =head2 include
41              
42             An C directive imports the definitions from another file, named
43             relative to the current file.
44              
45             include "filename.tan"
46              
47             =head2 class
48              
49             A C definition defines the set of methods, events and properties
50             defined by a named class.
51              
52             class N {
53             ...
54             }
55              
56             The contents of the class block will be a list of C, C, C
57             and C declarations.
58              
59             =head2 struct
60              
61             A C definition defines the list of fields contained within a named
62             structure type.
63              
64             struct N {
65             ...
66             }
67              
68             The contents of the struct block will be a list of C declarations.
69              
70             =cut
71              
72             has $_package;
73              
74             # Parser::MGC version 0.20 adds this method. Before then, this workaround is
75             # known to be safe
76             if( $Parser::MGC::VERSION < 0.20 ) {
77             *filename = sub ( $self ) { $self->{filename} };
78             }
79              
80             method parse
81 15     15 0 2141 {
82 15         84 dynamically $_package = \my %package;
83              
84 15         83 while( !$self->at_eos ) {
85             match( $self->token_kw(qw( class struct include )) : eq ) {
86             case( 'class' ) {
87 15         2142 my $classname = $self->token_ident;
88              
89 15 50       796 exists $package{$classname} and
90             $self->fail( "Already have a class or struct called $classname" );
91              
92 15         59 my $class = $self->make_class( name => $classname );
93 15         42 $package{$classname} = $class;
94              
95 15     15   123 $self->scope_of( '{', sub { $self->parse_classblock( $class ) }, '}' ),
  15         1359  
96             }
97             case( 'struct' ) {
98 11         816 my $structname = $self->token_ident;
99              
100 11 50       537 exists $package{$structname} and
101             $self->fail( "Already have a class or struct called $structname" );
102              
103 11         58 my $struct = $self->make_struct( name => $structname );
104 11         33 $package{$structname} = $struct;
105              
106 11     11   68 $self->scope_of( '{', sub { $self->parse_structblock( $struct ) }, '}' ),
  11         754  
107             }
108             case( 'include' ) {
109 2         378 my $filename = dirname($self->filename) . "/" . $self->token_string;
110              
111 2         389 my $subparser = (ref $self)->new;
112 2         11 my $included = $subparser->from_file( $filename );
113              
114 2         122 foreach my $classname ( keys %$included ) {
115 2 50       39 exists $package{$classname} and
116             $self->fail( "Cannot include '$filename' as class $classname collides" );
117              
118 2         22 $package{$classname} = $included->{$classname};
119             }
120             }
121 28 100       1716 default {
    100          
    50          
122 0         0 $self->fail( "Expected keyword, found $_" );
123             }
124             }
125             }
126              
127 15         1053 return \%package;
128             }
129              
130             =head2 method
131              
132             A C declaration defines one method in the class, giving its name (N)
133             and types of its arguments and and return (T).
134              
135             method N(T, T, ...) -> T;
136              
137             =head2 event
138              
139             An C declaration defines one event raised by the class, giving its name
140             (N) and types of its arguments (T).
141              
142             event N(T, T, ...);
143              
144             =head2 prop
145              
146             A C declaration defines one property supported by the class, giving its
147             name (N), dimension (D) and type (T). It may be declared as a C
148             property.
149              
150             [smashed] prop N = D of T;
151              
152             Scalar properties may omit the C, by supplying just the type
153              
154             [smashed] prop N = T;
155              
156             =head2 isa
157              
158             An C declaration declares a superclass of the class, by its name (C)
159              
160             isa C;
161              
162             =cut
163              
164 15         32 method parse_classblock ( $class )
  15         25  
  15         22  
165 15     15 0 134 {
166 15         56 my %methods;
167             my %events;
168 15         0 my %properties;
169 15         0 my @superclasses;
170              
171 15         49 while( !$self->at_eos ) {
172             match( $_ = $self->token_kw(qw( method event prop smashed isa )) : eq ) {
173             case( 'method' ) {
174 24         1774 my $methodname = $self->token_ident;
175              
176 24 50       1182 exists $methods{$methodname} and
177             $self->fail( "Already have a method called $methodname" );
178              
179 24         83 my $args = $self->parse_arglist;
180 24         1599 my $ret;
181              
182             $self->maybe( sub {
183 24     24   282 $self->expect( '->' );
184              
185 13         550 $ret = $self->parse_type;
186 24         121 } );
187              
188 24         862 $methods{$methodname} = $self->make_method(
189             class => $class,
190             name => $methodname,
191             arguments => $args,
192             ret => $ret,
193             );
194             }
195              
196             case( 'event' ) {
197 13         921 my $eventname = $self->token_ident;
198              
199 13 50       625 exists $events{$eventname} and
200             $self->fail( "Already have an event called $eventname" );
201              
202 13         105 my $args = $self->parse_arglist;
203              
204 13         803 $events{$eventname} = $self->make_event(
205             class => $class,
206             name => $eventname,
207             arguments => $args,
208             );
209             }
210              
211             case( 'smashed' ), case( 'prop' ) {
212 92         6430 my $smashed = 0;
213              
214 92 100       193 if( $_ eq 'smashed' ) {
215 24         41 $smashed = 1;
216 24         68 $self->expect( 'prop' );
217             }
218              
219 92         1180 my $propname = $self->token_ident;
220              
221 92 50       4399 exists $properties{$propname} and
222             $self->fail( "Already have a property called $propname" );
223              
224 92         218 $self->expect( '=' );
225              
226 92         3528 my $dim = DIM_SCALAR;
227             $self->maybe( sub {
228 92     92   1122 $dim = $self->parse_dim;
229 55         128 $self->expect( 'of' );
230 92         426 } );
231              
232 92         6212 my $type = $self->parse_type;
233              
234 92         494 $properties{$propname} = $self->make_property(
235             class => $class,
236             name => $propname,
237             smashed => $smashed,
238             dimension => $dim,
239             type => $type,
240             );
241             }
242              
243 131 100 100     7840 case( 'isa' ) {
    100          
    100          
    50          
244 2         176 my $supername = $self->token_ident;
245              
246 2 50       110 my $super = $_package->{$supername} or
247             $self->fail( "Unrecognised superclass $supername" );
248              
249 2         5 push @superclasses, $super;
250             }
251             }
252              
253 131         317 $self->expect( ';' );
254             }
255              
256             $class->define(
257 15         1025 methods => \%methods,
258             events => \%events,
259             properties => \%properties,
260             superclasses => \@superclasses,
261             );
262             }
263              
264             method parse_arglist
265 37     37 0 92 {
266             return $self->scope_of(
267             "(",
268 37     37   2102 sub { $self->list_of( ",", \&parse_arg ) },
269 37         171 ")",
270             );
271             }
272              
273             method parse_arg
274 48     48 0 2383 {
275 48         72 my $name;
276 48         114 my $type = $self->parse_type;
277             $self->maybe( sub {
278 48     48   552 $name = $self->token_ident;
279 48         392 } );
280 48         2908 return $self->make_argument( name => $name, type => $type );
281             }
282              
283 11         43 method parse_structblock ( $struct )
  11         22  
  11         17  
284 11     11 0 36 {
285 11         24 my @fields;
286             my %fieldnames;
287              
288 11         39 while( !$self->at_eos ) {
289             match( $self->token_kw(qw( field )) : eq ) {
290 55 50       3029 case( 'field' ) {
291 55         3865 my $fieldname = $self->token_ident;
292              
293 55 50       2598 exists $fieldnames{$fieldname} and
294             $self->fail( "Already have a field called $fieldname" );
295              
296 55         144 $self->expect( '=' );
297              
298 55         2275 my $type = $self->parse_type;
299              
300 55         382 push @fields, $self->make_field(
301             name => $fieldname,
302             type => $type,
303             );
304 55         123 $fieldnames{$fieldname}++;
305             }
306             }
307 55         135 $self->expect( ';' );
308             }
309              
310             $struct->define(
311 11         767 fields => \@fields,
312             );
313             }
314              
315             =head2 Types
316              
317             The following basic type names are recognised
318              
319             bool int str obj any
320             s8 s16 s32 s64 u8 u16 u32 u64
321              
322             Aggregate types may be formed of any type (T) by
323              
324             list(T) dict(T)
325              
326             =cut
327              
328             my @basic_types = qw(
329             bool
330             int
331             s8 s16 s32 s64 u8 u16 u32 u64
332             float
333             float16 float32 float64
334             str
335             obj
336             any
337             );
338              
339             method parse_type
340 219     219 0 1085 {
341             $self->any_of(
342             sub {
343 219     219   2652 my $aggregate = $self->token_kw(qw( list dict ));
344              
345 11         762 $self->commit;
346              
347 11         105 my $membertype = $self->scope_of( "(", \&parse_type, ")" );
348              
349 11         457 return $self->make_type( $aggregate => $membertype );
350             },
351             sub {
352 208     208   21728 my $typename = $self->token_ident;
353              
354 208 50       10053 grep { $_ eq $typename } @basic_types or
  3536         4712  
355             $self->fail( "'$typename' is not a typename" );
356              
357 208         511 return $self->make_type( $typename );
358             },
359 219         1089 );
360             }
361              
362             my %dimensions = (
363             scalar => DIM_SCALAR,
364             hash => DIM_HASH,
365             queue => DIM_QUEUE,
366             array => DIM_ARRAY,
367             objset => DIM_OBJSET,
368             );
369              
370             method parse_dim
371 92     92 0 199 {
372 92         295 my $dimname = $self->token_kw( keys %dimensions );
373              
374 55         3793 return $dimensions{$dimname};
375             }
376              
377             =head1 SUBCLASS METHODS
378              
379             If this class is subclassed, the following methods may be overridden to
380             customise the behaviour. They allow the subclass to return different objects
381             in the syntax tree.
382              
383             =cut
384              
385             =head2 make_class
386              
387             $class = $parser->make_class( name => $name )
388              
389             Return a new instance of L to go in a package. The
390             parser will call C on it.
391              
392             =cut
393              
394             method make_class
395 3     3 1 8 {
396 3         388 require Tangence::Meta::Class;
397 3         21 return Tangence::Meta::Class->new( @_ );
398             }
399              
400             =head2 make_struct
401              
402             $struct = $parser->make_struct( name => $name )
403              
404             Return a new instance of L to go in a package. The
405             parser will call C on it.
406              
407             =cut
408              
409             method make_struct
410 1     1 1 3 {
411 1         398 require Tangence::Meta::Struct;
412 1         9 return Tangence::Meta::Struct->new( @_ );
413             }
414              
415             =head2 make_method
416              
417             $method = $parser->make_method( %args )
418              
419             =head2 make_event
420              
421             $event = $parser->make_event( %args )
422              
423             =head2 make_property
424              
425             $property = $parser->make_property( %args )
426              
427             Return a new instance of L, L
428             or L to go in a class.
429              
430             =cut
431              
432             method make_method
433 24     24 1 55 {
434 24         465 require Tangence::Meta::Method;
435 24         153 return Tangence::Meta::Method->new( @_ );
436             }
437              
438             method make_event
439 13     13 1 43 {
440 13         408 require Tangence::Meta::Event;
441 13         109 return Tangence::Meta::Event->new( @_ );
442             }
443              
444             method make_property
445 10     10 1 19 {
446 10         377 require Tangence::Meta::Property;
447 10         44 return Tangence::Meta::Property->new( @_ );
448             }
449              
450             =head2 make_argument
451              
452             $argument = $parser->make_argument( %args )
453              
454             Return a new instance of L to use for a method
455             or event argument.
456              
457             =cut
458              
459             method make_argument
460 48     48 1 108 {
461 48         598 require Tangence::Meta::Argument;
462 48         249 return Tangence::Meta::Argument->new( @_ );
463             }
464              
465             =head2 make_field
466              
467             $field = $parser->make_field( %args )
468              
469             Return a new instance of L to use for a structure type.
470              
471             =cut
472              
473             method make_field
474 55     55 1 108 {
475 55         617 require Tangence::Meta::Field;
476 55         249 return Tangence::Meta::Field->new( @_ );
477             }
478              
479             =head2 make_type
480              
481             $type = $parser->make_type( $primitive_name )
482              
483             $type = $parser->make_type( $aggregate_name => $member_type )
484              
485             Return an instance of L representing the given
486             primitive or aggregate type name. An implementation is allowed to use
487             singleton objects and return identical objects for the same primitive name or
488             aggregate and member type.
489              
490             =cut
491              
492             method make_type
493 24     24 1 58 {
494 24         462 require Tangence::Meta::Type;
495 24         69 return Tangence::Meta::Type->make( @_ );
496             }
497              
498             =head1 AUTHOR
499              
500             Paul Evans
501              
502             =cut
503              
504             0x55AA;