4 # -t package target package
5 # -d directory output root
7 # -a datafile add datafile to the dataset, can be from export.so or export-defines, etc
11 use File::Path qw(make_path);
18 use lib "$FindBin::Bin/../lib";
24 $SIG{ __DIE__ } = sub { Carp::confess( @_ ) };
25 $Data::Dumper::Indent = 1;
27 my $apidef = "api.api";
38 if ($cmd =~ m/^(-[^-])(.+)/) {
44 $vars->{package} = shift;
45 } elsif ($cmd eq "-d") {
46 $vars->{output} = shift;
47 } elsif ($cmd eq "-I") {
48 push @{$vars->{include}}, shift;
49 } elsif ($cmd eq "-v") {
51 } elsif ($cmd eq "-a") {
58 push @{$vars->{include}}, "$FindBin::Bin/../lib";
60 print Dumper($vars) if $vars->{verbose};
62 my $api = new api($apidef, $vars, @apilist);
66 exportLibraries($api);
68 exportConstants($api);
75 my $info = new method($api, $c);
77 #print 'function='.Dumper($c);
78 #print 'members='.Dumper(\@members);
79 #print 'info='.Dumper($info);
83 #foreach my $l (split /\n/,Dumper($info->{vars}).Dumper($info->{arguments})) {
87 $code .= code::applyTemplate($template, $info->{vars});
88 $code =~ s/^\s*\n//osgm;
96 my $template = $api->{index}->{'code:method'};
97 my $upcall = api::findItem($template, 'upcall');
98 my $downcall = api::findItem($template, 'downcall');
99 my $info = new method($api, $c);
101 #print 'function='.Dumper($c);
102 #print 'members='.Dumper(\@members);
105 foreach my $l (split /\n/,Dumper($info)) {
109 $info->{vars}->{downcall} = ($c->{access} =~ m/r/) ? code::applyTemplate($downcall, $info->{vars}) : '';
110 $info->{vars}->{upcall} = ($c->{access} =~ m/w/) ? code::applyTemplate($upcall, $info->{vars}) : '';
112 return $code.code::applyTemplate(api::findItem($api->{index}->{'code:class'}, 'call'), $info->{vars});
123 $api->{output}->{"$_->{type}:$_->{name}"}++;
124 $res->{seen}->{"$_->{type}:$_->{name}"}++ == 0
125 } $api->findMatches($inc);
127 if ($inc->{type} eq 'func') {
128 my $def = $api->{index}->{'func:<default>'};
129 my $func = api::optionValue('func:template', 'code:method=invoke', $inc, $res->{template});
130 my $init = api::optionValue('init:template', undef, $inc, $res->{template});
131 my $funct = findTemplateName($api, $func);
132 my $initt = findTemplateName($api, $init) if defined $init;
134 push @{$res->{func}}, map { formatFunction($api, $_, $funct) } @list;
135 push @{$res->{init}}, map { formatFunction($api, $_, $initt) } @list if defined($initt);
136 } elsif ($inc->{type} eq 'define') {
137 push @{$res->{define}}, map { code::formatDefine($api, $_) } @list;
138 } elsif ($inc->{type} eq 'enum') {
139 push @{$res->{enum}}, map { code::formatEnum($api, $_) } @list;
140 } elsif ($inc->{type} eq 'call') {
141 push @{$res->{enum}}, map { formatCall($api, $_) } @list;
151 my $data = $api->{data};
154 print "library $obj->{name}\n" if ($api->{vars}->{verbose} > 0);
156 foreach my $inc (@{$obj->{items}}) {
157 if ($inc->{type} eq 'library') {
158 $api->{output}->{"$inc->{match}"}++;
159 formatLibrary($api, $api->{index}->{$inc->{match}}, $res);
160 } elsif ($inc->{type} =~ m/^(func|call|define|enum)$/no) {
161 print " $inc->{match}\n" if ($api->{vars}->{verbose} > 1);
162 formatItems($api, $obj, $inc, $res);
163 } elsif ($inc->{match} eq 'code:<inline>') {
164 print " $inc->{match}\n" if ($api->{vars}->{verbose} > 1);
165 push @{$res->{func}}, $inc->{literal};
166 } elsif ($inc->{type} eq 'code') {
167 # apply template perhaps, or apply with set?
168 push @{$res->{func}}, map {
169 if (defined($inc->{options}->[0])) {
170 api::findItem($_, $inc->{options}->[0])->{literal};
174 } grep { $_->{match} =~ m/$inc->{regex}/ } @{$api->{api}};
175 } elsif ($inc->{type} ne 'field') {
182 sub findTemplateName {
186 if ($name =~ m/^(.+)=(.+)$/) {
187 my $template = api::findItem($api->{index}->{$1}, $2);
188 return $template if defined $template;
190 die "can't find template '$name'\n";
197 my $data = $api->{data};
198 my $def = $api->{index}->{"$s->{type}:<default>"};
199 my $name = api::optionValue('template', $s->{size} == 0 ? 'code:class=handle' : 'code:class=struct', $obj, $def);
201 return findTemplateName($api, $name);
204 # TODO: embedded structs
209 my $data = $api->{data};
211 my $structTemplate = findTemplate($api, $obj, $s);
212 my @members = code::scanFields($api, $s);
213 my @membersOutput = grep { $_->{field}->{output} } @members;
215 my $varhandles = join '', map { code::formatTemplate($_->{match}->{varhandle}, $_->{match}, "\t") } @membersOutput;
216 my $accessors = join "\n", map {
217 my ($m, $type, $match) = ($_->{field}, $_->{type}, $_->{match});
219 my $accessor = $api->{index}->{$_};
221 map { code::applyTemplate($_, $match) } grep { $_ } map { api::findItem($accessor, $_) } map {
225 push @list, 'geti' if $_ =~ m/i/o;
229 push @list, 'seti' if $_ =~ m/i/o;
233 } split(/,/,api::optionValue('template', undef, $type));
243 template => $structTemplate,
246 formatLibrary($api, $obj, $res);
250 layout => code::formatStructLayout($api, $s, \@members),
251 rename => $s->{rename},
253 varhandles => $varhandles,
254 accessors => $accessors,
255 methods => join("\n", @{$res->{func}}),
256 defines => join("\n", @{$res->{define}}),
257 enums => join("\n", @{$res->{enum}}),
261 foreach my $l (split /\n/,Dumper($s, \@members)) {
265 $api->{output}->{"$s->{type}:$s->{name}"} = 1;
267 return $code.code::applyTemplate($structTemplate, $vars);
270 # output all libraries
271 sub exportLibraries {
273 my $data = $api->{data};
274 my $def = $api->{index}->{'library:<default>'};
276 foreach my $obj (grep { $_->{type} eq 'library' } @{$api->{api}}) {
277 next if $api->{output}->{"$obj->{type}:$obj->{name}"};
278 next if $obj->{output} != 1;
280 my $library = findTemplateName($api, api::optionValue('template', 'code:class=library', $obj, $def));
289 template => $library,
292 formatLibrary($api, $obj, $res);
296 name => $obj->{name},
297 init => join("\n", @{$res->{init}}),
298 defines => join("\n", @{$res->{define}}),
299 enums => join("\n", @{$res->{enum}}),
300 funcs => join("\n", @{$res->{func}}),
301 calls => join("\n", @{$res->{call}}),
304 export($api, $obj->{name}, code::applyTemplate($library, $vars));
313 my $f = $api->openOutput($name);
315 $api->closeOutput($name, $f);
323 if ($s->{type} =~ m/struct|union/) {
324 return formatStruct($api, $obj, $s);
325 } elsif ($s->{type} eq 'call') {
326 return formatCall($api, $s);
334 my $data = $api->{data};
336 # first those directly referenced
337 foreach my $obj (grep { $_->{type} =~ m/call|struct|union/ } @{$api->{api}}) {
338 my @list = $api->findMatches($obj);
340 print "gen ".($#list+1)." $obj->{type} $obj->{name}\n" if ($api->{vars}->{verbose} > 0);
341 foreach my $s (@list) {
342 next if $api->{output}->{"$s->{type}:$s->{name}"};
343 print " $s->{name}\n" if ($api->{vars}->{verbose} > 1);
345 export($api, $s->{rename}, formatClass($api, $obj, $s));
349 # then anything else left using the default outputs
350 foreach my $s (grep { $_->{output} && ($_->{type} =~ m/struct|union|call/) && !$api->{output}->{"$_->{type}:$_->{name}"} } @{$api->{api}}) {
351 my $obj = $data->{"$s->{type}:<default>"};
352 export($api, $s->{rename}, formatClass($api, $obj, $s));
356 # exports any define/enum not yet included elsehwere
357 # TODO: this is sort of not very useful
358 sub exportConstants {
360 my $data = $api->{data};
361 my $template = $api->{index}->{'code:class'};
362 my $constant = api::findItem($template, 'constants');
364 # hmm, not sure if i should use obj or just the values directly here
365 foreach my $s (grep { $_->{type} =~ m/define|enum/ } values %{$api->{data}}) {
366 next if $api->{output}->{"$s->{type}:$s->{name}"};
367 next if !$s->{output};
372 $defines = code::formatDefine($api, $s) if $s->{type} eq 'define';
373 $enums = code::formatEnum($api, $s) if $s->{type} eq 'enum';
383 foreach my $l (split /\n/,Dumper($s)) {
387 export($api, $s->{name}, $code.code::applyTemplate($constant, $vars));