source: trunk/PERL2ARB/extract_perl_interface.pl

Last change on this file was 19047, checked in by westram, 3 years ago
  • Property svn:executable set to *
File size: 5.7 KB
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5
6my $ARBHOME = $ENV{ARBHOME};
7defined $ARBHOME || die "Expected environment variable ARBHOME to be defined";
8-d $ARBHOME || die "Expected directory '$ARBHOME' (from environment variable ARBHOME)";
9
10my $ARBPERLDIR = $ARBHOME.'/PERL2ARB';
11-d $ARBPERLDIR || die "Expected directory '$ARBPERLDIR'";
12
13my %method = (); # ARB::name or BIO::name (value=1)
14my %name   = (); # key = method, value = name only
15
16sub parsePerlMethods() {
17  my $arb_c = $ARBPERLDIR.'/ARB.c';
18  open(CSRC, '<'.$arb_c) || die "failed to read '$arb_c' (Reason: $!)";
19
20  my $line;
21  my $reg = qr/(newXSproto|newXSproto_portable).*\"(ARB|BIO)::([a-zA-Z0-9_]+)\"/o;
22  while (defined($line=<CSRC>)) {
23    if ($line =~ $reg) {
24      my ($package,$name) = ($2,$3);
25      my $method = $package.'::'.$name;
26      if (exists $method{$method}) {
27        die "duplicated method '$method'";
28      }
29      $method{$method} = 1;
30      $name{$method} = $name;
31    }
32  }
33
34  close(CSRC);
35  if (scalar(keys %method)<1) {
36    die "No 'ARB perl interface'-functions detected in '$arb_c' (parsing error?)";
37  }
38}
39
40my %prototype = (); # key = c++ method name, value=full prototype OR 0 (if duplicated)
41my %file      = (); # key = method name, value=filename OR undef (if duplicated)
42
43sub parsePrototypes() {
44  my $proto_h = $ARBPERLDIR.'/proto.h';
45  open(PROTO, '<'.$proto_h) || die "failed to read '$proto_h' (Reason: $!)";
46
47  my $line;
48  my $reg_file_start = qr/\/\*\s*([^\s]+)\s*\*\//o;
49  my $reg_prototype = qr/([a-zA-Z0-9_]+)\(/o;
50
51  my $current_file = undef;
52
53  while (defined($line=<PROTO>)) {
54    if ($line =~ $reg_prototype) {
55      my $name = $1;
56      chomp($line);
57      if (exists $prototype{$name}) {
58        $prototype{$name} = 0; # duplicated function name
59        $file{$name} = undef;
60      }
61      else {
62        $prototype{$name} = $line;
63        $file{$name} = $current_file;
64      }
65    }
66    elsif ($line =~ $reg_file_start) {
67      my ($file) = $1;
68      if ($file =~ /\.cxx$/o) { $current_file = $file; }
69      # else { print "ignored file '$file'\n"; }
70    }
71  }
72
73  close(PROTO);
74  if (scalar(keys %prototype)<1) {
75    die "No 'ARB perl interface'-functions detected in '$proto_h' (parsing error?)";
76  }
77
78  # hardcoded methods:
79  $prototype{GB_await_error} = 'GB_ERROR GB_await_error(void);';
80  $file{GB_await_error} = '../CORE/arb_msg.cxx';
81
82  $prototype{GBP_prepare_to_die} = 'void GBP_prepare_to_die()';
83  $file{GBP_prepare_to_die} = 'adperl.cxx';
84}
85
86my %cpp_method = (); # key = perl method (full), value=C++ method
87
88sub linkMethods() {
89  my $reg_cpp_method = qr/^([^_]+)_(.*)$/o;
90
91  # see also ../PERLTOOLS/arb_proto_2_xsub.cxx@PREFIX_HANDLING
92  my %ppackage =
93    (
94     'GB' => 'ARB',
95     'GBP' => 'ARB',
96     'GBT' => 'BIO',
97     'GEN' => 'BIO',
98    );
99
100  foreach my $cpp_method (sort keys %prototype) {
101    if ($cpp_method =~ $reg_cpp_method) {
102      my ($prefix,$name) = ($1,$2);
103      my $package = $ppackage{$prefix};
104      if (defined $package) {
105        my $perl_method = $package.'::'.$name;
106        if (exists $method{$perl_method}) {
107          if (exists $cpp_method{$perl_method}) {
108            die "ambiguous function suffix matches for '$perl_method': $cpp_method and ".$cpp_method{$perl_method};
109          }
110          $cpp_method{$perl_method} = $cpp_method;
111        }
112        # else { print STDERR "Note: Found no perl-method for prototype '$cpp_method'\n"; } # shows unused prototypes
113      }
114      # else { print STDERR "Note: no package defined for prefix '$prefix' (cpp_method=$cpp_method)\n"; }
115    }
116    else {
117      die "cannot parse method name: '$cpp_method'";
118    }
119  }
120
121  foreach my $perl_method (sort keys %method) {
122    if (not exists $cpp_method{$perl_method}) {
123      die "failed to detect c++-function for '$perl_method'";
124      # print "Error: failed to detect c++-function for '$perl_method'\n";
125    }
126  }
127}
128
129my $HEADER = <<'END_HEADER';
130#
131# The list below contains information about the functions provided by the arb PERL interface.
132#
133# The columns contain the following information:
134# - function name (used to sort; not unique),
135# - fully qualified name of perl function (unique),
136# - name of C++ function and
137# - name of C++ file where function is located.
138#
139# The list is automatically updated while arb is build.
140#
141# To find specific information for single C++ functions, refer to
142#     http://dev.arb-home.de/source_doc/globals_func_g.html#index_g
143# look there for the C++ function name (3rd column below) and
144# click on one of the links behind the name.
145#
146# If no documentation is shown then, please also click on the line number at
147#     "Definition at line ### of file MODULE.cxx."
148# to look into the source code, which may contain documenting comments.
149#
150END_HEADER
151
152sub dumpMethods() {
153  my @sorted_method = sort {
154    my $cmp = $name{$a} cmp $name{$b};
155    if ($cmp == 0) {
156      $cmp = $a cmp $b;
157    }
158    $cmp;
159  } keys %method;
160
161  my $name_width = 47;
162  my $full_width = $name_width + 5;
163  my $cpp_width  = $name_width + 3 + 1;
164
165  print $HEADER;
166
167  foreach my $perl_method (@sorted_method) {
168    my $name = $name{$perl_method};
169    my $name_length = length($name);
170    if ($name_length > $name_width) { die "bad formatting: name_width < $name_length"; }
171
172    my $cpp = $cpp_method{$perl_method};
173    my $cpp_length = length($cpp);
174    if ($cpp_length > $cpp_width) { die "bad formatting: cpp_width < $cpp_length"; }
175
176    my $file = $file{$cpp};
177
178    if (not defined $file) {
179       die "Error: ambiguous function definition for '$cpp' (overloaded method exported to perl?)\n";
180    }
181    else {
182      print sprintf('%-'.$name_width.'s %-'.$full_width.'s %-'.$cpp_width.'s %s'."\n", $name, $perl_method, $cpp, $file);
183    }
184  }
185}
186
187sub main() {
188  parsePerlMethods();
189  parsePrototypes();
190  linkMethods();
191
192  dumpMethods();
193}
194
195main();
Note: See TracBrowser for help on using the repository browser.