#!/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
# -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 = ();
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/;
} 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") {
}
use Data::Dumper;
-print Dumper(@classes);
#exit 0;
require $meta;
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;
# 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}};
}
}
-# 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}};
}
}
+# 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)$/;
}
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) {
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);
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(";