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";
59 push @INC, dirname($apidef);
61 print Dumper($vars) if $vars->{verbose};
63 my $api = new api($apidef, $vars, @apilist);
67 exportLibraries($api);
69 exportConstants($api);
76 my $info = new method($api, $c);
78 #print 'function='.Dumper($c);
79 #print 'members='.Dumper(\@members);
80 #print 'info='.Dumper($info);
84 #foreach my $l (split /\n/,Dumper($info->{vars}).Dumper($info->{arguments})) {
88 $code .= code::applyTemplate($template, $info->{vars});
89 $code =~ s/^\s*\n//osgm;
97 my $template = $api->{index}->{'code:method'};
98 my $upcall = api::findItem($template, 'upcall');
99 my $downcall = api::findItem($template, 'downcall');
100 my $info = new method($api, $c);
102 #print 'function='.Dumper($c);
103 #print 'members='.Dumper(\@members);
106 foreach my $l (split /\n/,Dumper($info)) {
110 $info->{vars}->{downcall} = ($c->{access} =~ m/r/) ? code::applyTemplate($downcall, $info->{vars}) : '';
111 $info->{vars}->{upcall} = ($c->{access} =~ m/w/) ? code::applyTemplate($upcall, $info->{vars}) : '';
113 return $code.code::applyTemplate(api::findItem($api->{index}->{'code:class'}, 'call'), $info->{vars});
124 $api->{output}->{"$_->{type}:$_->{name}"}++;
125 $res->{seen}->{"$_->{type}:$_->{name}"}++ == 0
126 } $api->findMatches($inc, $res->{ctx});
128 if ($inc->{type} eq 'func') {
129 my $def = $api->{index}->{'func:<default>'};
130 my $func = api::optionValue('func:template', 'code:method=invoke', $inc, $res->{template});
131 my $init = api::optionValue('init:template', undef, $inc, $res->{template});
132 my $funct = findTemplateName($api, $func);
133 my $initt = findTemplateName($api, $init) if defined $init;
135 push @{$res->{func}}, map { formatFunction($api, $_, $funct) } @list;
136 push @{$res->{init}}, map { formatFunction($api, $_, $initt) } @list if defined($initt);
137 } elsif ($inc->{type} eq 'define') {
138 push @{$res->{define}}, map { code::formatDefine($api, $_) } @list;
139 } elsif ($inc->{type} eq 'enum') {
140 push @{$res->{enum}}, map { code::formatEnum($api, $_) } @list;
141 } elsif ($inc->{type} eq 'call') {
142 push @{$res->{enum}}, map { formatCall($api, $_) } @list;
152 my $data = $api->{data};
155 print "library $obj->{name}\n" if ($api->{vars}->{verbose} > 0);
157 foreach my $inc (@{$obj->{items}}) {
158 if ($inc->{type} eq 'library') {
159 $api->{output}->{"$inc->{match}"}++;
160 formatLibrary($api, $api->{index}->{$inc->{match}}, $res);
161 } elsif ($inc->{type} =~ m/^(func|call|define|enum)$/no) {
162 print " $inc->{match}\n" if ($api->{vars}->{verbose} > 1);
163 formatItems($api, $obj, $inc, $res);
164 } elsif ($inc->{match} eq 'code:<inline>') {
165 print " $inc->{match}\n" if ($api->{vars}->{verbose} > 1);
166 push @{$res->{func}}, $inc->{literal};
167 } elsif ($inc->{type} eq 'code') {
168 # apply template perhaps, or apply with set?
169 push @{$res->{func}}, map {
170 if (defined($inc->{options}->[0])) {
171 api::findItem($_, $inc->{options}->[0])->{literal};
175 } grep { $_->{match} =~ m/$inc->{regex}/ } @{$api->{api}};
176 } elsif ($inc->{type} ne 'field') {
183 sub findTemplateName {
187 if ($name =~ m/^(.+)=(.+)$/) {
188 my $template = api::findItem($api->{index}->{$1}, $2);
189 return $template if defined $template;
191 die "can't find template '$name'\n";
198 my $data = $api->{data};
199 my $def = $api->{index}->{"$s->{type}:<default>"};
200 my $name = api::optionValue('template', $s->{size} == 0 ? 'code:class=handle' : 'code:class=struct', $obj, $def);
202 return findTemplateName($api, $name);
205 # TODO: embedded structs
210 my $data = $api->{data};
212 my $structTemplate = findTemplate($api, $obj, $s);
213 my @members = code::scanFields($api, $s);
214 my @membersOutput = grep { $_->{field}->{output} } @members;
216 my $varhandles = join '', map { code::formatTemplate($_->{match}->{varhandle}, $_->{match}, "\t") } @membersOutput;
217 my $accessors = join "\n", map {
218 my ($m, $type, $match) = ($_->{field}, $_->{type}, $_->{match});
220 my $accessor = $api->{index}->{$_};
222 map { code::applyTemplate($_, $match) } grep { $_ } map { api::findItem($accessor, $_) } map {
226 push @list, 'geti' if $_ =~ m/i/o;
230 push @list, 'seti' if $_ =~ m/i/o;
234 } split(/,/,api::optionValue('template', undef, $type));
245 template => $structTemplate,
248 formatLibrary($api, $obj, $res);
252 layout => code::formatStructLayout($api, $s, \@members),
253 rename => $s->{rename},
255 varhandles => $varhandles,
256 accessors => $accessors,
257 methods => join("\n", @{$res->{func}}),
258 defines => join("\n", @{$res->{define}}),
259 enums => join("\n", @{$res->{enum}}),
263 foreach my $l (split /\n/,Dumper($s, \@members)) {
267 $api->{output}->{"$s->{type}:$s->{name}"} = 1;
269 return $code.code::applyTemplate($structTemplate, $vars);
272 # output all libraries
273 sub exportLibraries {
275 my $data = $api->{data};
276 my $def = $api->{index}->{'library:<default>'};
278 foreach my $obj (grep { $_->{type} eq 'library' } @{$api->{api}}) {
279 next if $api->{output}->{"$obj->{type}:$obj->{name}"};
280 next if $obj->{output} != 1;
282 my $library = findTemplateName($api, api::optionValue('template', 'code:class=library', $obj, $def));
292 template => $library,
295 formatLibrary($api, $obj, $res);
299 name => $obj->{name},
300 init => join("\n", @{$res->{init}}),
301 defines => join("\n", @{$res->{define}}),
302 enums => join("\n", @{$res->{enum}}),
303 funcs => join("\n", @{$res->{func}}),
304 calls => join("\n", @{$res->{call}}),
307 export($api, $obj->{name}, code::applyTemplate($library, $vars));
316 my $f = $api->openOutput($name);
318 $api->closeOutput($name, $f);
326 if ($s->{type} =~ m/struct|union/) {
327 return formatStruct($api, $obj, $s);
328 } elsif ($s->{type} eq 'call') {
329 return formatCall($api, $s);
337 my $data = $api->{data};
339 # first those directly referenced
340 foreach my $obj (grep { $_->{type} =~ m/call|struct|union/ } @{$api->{api}}) {
341 my @list = $api->findMatches($obj, $obj);
343 print "gen ".($#list+1)." $obj->{type} $obj->{name}\n" if ($api->{vars}->{verbose} > 0);
344 foreach my $s (@list) {
345 next if $api->{output}->{"$s->{type}:$s->{name}"};
346 print " $s->{name}\n" if ($api->{vars}->{verbose} > 1);
348 export($api, $s->{rename}, formatClass($api, $obj, $s));
352 # then anything else left using the default outputs
353 foreach my $s (grep { $_->{output} && ($_->{type} =~ m/struct|union|call/) && !$api->{output}->{"$_->{type}:$_->{name}"} } @{$api->{api}}) {
354 my $obj = $data->{"$s->{type}:<default>"};
355 export($api, $s->{rename}, formatClass($api, $obj, $s));
359 # exports any define/enum not yet included elsehwere
360 # TODO: this is sort of not very useful
361 sub exportConstants {
363 my $data = $api->{data};
364 my $template = $api->{index}->{'code:class'};
365 my $constant = api::findItem($template, 'constants');
367 # hmm, not sure if i should use obj or just the values directly here
368 foreach my $s (grep { $_->{type} =~ m/define|enum/ } values %{$api->{data}}) {
369 next if $api->{output}->{"$s->{type}:$s->{name}"};
370 next if !$s->{output};
375 $defines = code::formatDefine($api, $s) if $s->{type} eq 'define';
376 $enums = code::formatEnum($api, $s) if $s->{type} eq 'enum';
386 foreach my $l (split /\n/,Dumper($s)) {
390 export($api, $s->{name}, $code.code::applyTemplate($constant, $vars));