From f2c2e66ac51edb6f2458d4d98216e04dc5ddda13 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Thu, 9 Jan 2020 07:01:32 +1030 Subject: [PATCH] Output enum definitions. --- src/generate | 119 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 19 deletions(-) diff --git a/src/generate b/src/generate index bc7ee2b..e6eaf8c 100755 --- a/src/generate +++ b/src/generate @@ -1,7 +1,7 @@ #!/usr/bin/perl # usage -# generate [-d dir] [-t package] [--enclosing-type type ] [-s struct-root-pattern]* [--struct-file file]* [-c class [-llib]* [-f func-pattern]* [--func-file file]* ]* +# generate [-d dir] [-t package] [--enclosing-type type ] [-s struct-root-pattern]* [--struct-file file]* [-c class [-llib]* [-f func-pattern]* [--func-file file]* [-e enum-pattern]]* # -d dir # root output directory # -t package @@ -20,18 +20,22 @@ # -llib # specify link library used by class # -f func-pattern -# function name pattern to include for the last class +# function name pattern to include for the current class # --func-file file # point to a filename with exact function names in it, one per line ('#' is a comment). +# -e enum-pattern +# enum name pattern to include for the current class +# --enum-file file +# filename with enums in it # TODO: scan all functions and include any types they use as struct roots # TODO: some way to specify external types @matchStruct = (); $meta = ""; -# @classes = ( { name => 'class', match => [ func-pattern, ... ], match_file => [ file, ... ] } ) +# @classes = ( { name => 'class', match => [ func-pattern, ... ], match_file => [ file, ... ], enum => [ enum-pattern, ... ], enum_file => [ file, ...] } ) @classes = (); -%lastclass = (); +%class = (); $output = "."; # map call signatures to a class name %callMap = (); @@ -42,11 +46,19 @@ while (@ARGV) { if ($cmd eq "-f") { my $v = shift(@ARGV); - push @{$lastclass{match}}, qr/$v/; + push @{$class{match}}, qr/$v/; } elsif ($cmd eq "--func-file") { my $file = shift(@ARGV); - push @{$lastclass{match_file}}, $file; - push @{$lastclass{match}}, readMatchFile($file); + + push @{$class{match_file}}, $file; + push @{$class{match}}, readMatchFile($file); + } elsif ($cmd eq "-e") { + my $v = shift(@ARGV); + push @{$class{enum}}, qr/$v/; + } elsif ($cmd eq "--enum-file") { + my $file = shift(@ARGV); + push @{$class{enum_file}}, $file; + push @{$class{enum}}, readMatchFile($file); } elsif ($cmd eq "-s") { my $v = shift(@ARGV); push @matchStruct, qr/$v/; @@ -56,14 +68,18 @@ while (@ARGV) { } elsif ($cmd eq "-t") { $package = shift(@ARGV); } elsif ($cmd eq "-c") { - %lastclass = ( + my %new = ( name => shift(@ARGV), match => [], match_file => [], + enum => [], + enum_file => [], libs => []); - push @classes, \%lastclass; + push @classes, \%new; + %class = %new; + print "new:\n".Dumper(\%class); } elsif ($cmd =~ m/^-l(.*)/) { - push @{$lastclass{libs}}, $1; + push @{$class{libs}}, $1; } elsif ($cmd eq "-d") { $output = shift(@ARGV); } elsif ($cmd eq "--enclosing-type") { @@ -74,7 +90,6 @@ while (@ARGV) { } use Data::Dumper; -print Dumper(@classes); #exit 0; require $meta; @@ -453,12 +468,13 @@ sub findStructs { return keys %visit; } -sub findFuncs { +sub findDefinition { my %all = %{shift @_}; + my $type = shift @_; my @match = @_; my @stack = grep { my %e = %{$all{$_}}; - $e{type} eq "func" && testMatch($e{name}, @match); + $e{type} eq $type && testMatch($e{name}, @match); } keys %all; return @stack; @@ -468,14 +484,14 @@ sub findFuncs { # setup section -# find all classes used by functions, add them to the struct roots +# find all classes used by functions my %roots = (); for $c (@classes) { my %class = %{$c}; my @libs = @{$class{libs}}; my @match = @{$class{match}}; - for $k (findFuncs(\%data, @match)) { + for $k (findDefinition(\%data, 'func', @match)) { my %func = %{$data{$k}}; my @params = @{$func{arguments}}; @@ -495,8 +511,8 @@ for $c (@classes) { } } -# FIXME: only include ones used elsewhere # add roots for any types used by calls +# FIXME: only include ones used elsewhere for $k (grep { $_ =~ m/^call:/n } keys %data) { my %func = %{$data{$k}}; my @params = @{$func{arguments}}; @@ -516,6 +532,22 @@ for $k (grep { $_ =~ m/^call:/n } keys %data) { } } +# Create anonymous structs for anything missing +for $k (keys %roots) { + my $s = 'struct:'.$k; + my $u = 'union:'.$k; + + if (!$data{$u} && !$data{$s}) { + print " anon: $s\n"; + my %rec = ( + type => 'struct', + name => $k, + size => 0 + ); + $data{$s} = \%rec; + } +} + $all = join ('|', keys %roots); if ($all) { push @matchStruct, qr/^($all)$/; @@ -625,7 +657,9 @@ END } my $resolve = join (",", keys %resolve); - print $dst "\@NativeStruct(value=\"$signature($struct{name})\", resolutionContext={$resolve})\n"; + print $dst "\@NativeStruct(value=\"$signature($struct{name})\""; + print $dst ", resolutionContext={$resolve}" if ($resolve); + print $dst ")\n"; print $dst "public interface $name extends Struct<$name> {\n"; for $fi (@fields) { @@ -681,7 +715,38 @@ END print $dst "})\n"; print $dst "public interface $class{name} {\n"; - for $k (sort(findFuncs(\%data, @match))) { + # enums to ints + # TODO: interfaces? + # TODO: static lib class? + # typedef enums might appear twice in the data, so ignore duplicates + # also, some api's have multiple definitions (?) + my %visited = (); + my @match_enum = @{$class{enum}}; + for $k (sort(findDefinition(\%data, 'enum', @match_enum))) { + my %enum = %{$data{$k}}; + my @values = @{$enum{values}}; + my $type = "int"; + + if ($enum{value_type} =~ m/^[ui](\d+)/) { + $type = "long" if ($1 > 32) + } + + print $dst "\n\t// enum $enum{name}\n"; + for $vi (@values) { + my %value = %{$vi}; + + if (!$visited{$value{label}}) { + #print $dst "\tpublic static final $type $value{label} = ($type)$value{value};\n"; + print $dst "\tpublic static final $type $value{label} = $value{value};\n"; + $visited{$value{label}} = 1; + } + } + } + + # functions + print "class $class{name} -> match:\n".Dumper(\@match); + + for $k (sort(findDefinition(\%data, 'func', @match))) { my %func = %{$data{$k}}; my @params = @{$func{arguments}}; my $signature = funcSignature(\%func); @@ -742,9 +807,25 @@ import java.foreign.memory.*; END } + # any in-line structures need to be added to the resolutionContext + # TODO: only include actual inline, not pointers + my %resolve = (); + my @list = @params; + unshift(@list,$call{result}); + for $pi (@list) { + my %param = %{$pi}; + + if ($param{type} =~ m/^(struct|union):(.*)/) { + $resolve{StudlyCaps($2).".class"} = 1; + } + } + my $resolve = join (",", keys %resolve); + # FIXME: use something other than name to store this print $dst "\@FunctionalInterface\n"; - print $dst "\@NativeCallback(value=\"$call{name}\")\n"; + print $dst "\@NativeCallback(value=\"$call{name}\""; + print $dst ", resolutionContext={$resolve}" if ($resolve); + print $dst ")\n"; print $dst "public interface $name {\n"; print $dst "\tpublic $result fn("; -- 2.39.5