Access GCController instance via GCController::singleton() instead of a free function
[WebKit-https.git] / Source / WebCore / bindings / scripts / generate-bindings.pl
1 #!/usr/bin/perl -w
2 #
3 # Copyright (C) 2005 Apple Inc.
4 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
5
6 # This file is part of WebKit
7
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Library General Public License for more details.
17
18 # You should have received a copy of the GNU Library General Public License
19 # along with this library; see the file COPYING.LIB.  If not, write to
20 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 # Boston, MA 02110-1301, USA.
22
23
24 # This script is a temporary hack. 
25 # Files are generated in the source directory, when they really should go
26 # to the DerivedSources directory.
27 # This should also eventually be a build rule driven off of .idl files
28 # however a build rule only solution is blocked by several radars:
29 # <rdar://problems/4251781&4251785>
30
31 use strict;
32
33 use File::Path;
34 use File::Basename;
35 use Getopt::Long;
36 use Text::ParseWords;
37 use Cwd;
38
39 use IDLParser;
40 use CodeGenerator;
41
42 my @idlDirectories;
43 my $outputDirectory;
44 my $outputHeadersDirectory;
45 my $generator;
46 my $defines;
47 my $filename;
48 my $prefix;
49 my $preprocessor;
50 my $writeDependencies;
51 my $verbose;
52 my $supplementalDependencyFile;
53 my $additionalIdlFiles;
54 my $idlAttributesFile;
55
56 GetOptions('include=s@' => \@idlDirectories,
57            'outputDir=s' => \$outputDirectory,
58            'outputHeadersDir=s' => \$outputHeadersDirectory,
59            'generator=s' => \$generator,
60            'defines=s' => \$defines,
61            'filename=s' => \$filename,
62            'prefix=s' => \$prefix,
63            'preprocessor=s' => \$preprocessor,
64            'verbose' => \$verbose,
65            'write-dependencies' => \$writeDependencies,
66            'supplementalDependencyFile=s' => \$supplementalDependencyFile,
67            'additionalIdlFiles=s' => \$additionalIdlFiles,
68            'idlAttributesFile=s' => \$idlAttributesFile);
69
70 my $targetIdlFile = $ARGV[0];
71
72 die('Must specify input file.') unless defined($targetIdlFile);
73 die('Must specify generator') unless defined($generator);
74 die('Must specify output directory.') unless defined($outputDirectory);
75
76 if (!$outputHeadersDirectory) {
77     $outputHeadersDirectory = $outputDirectory;
78 }
79 $targetIdlFile = Cwd::realpath($targetIdlFile);
80 if ($verbose) {
81     print "$generator: $targetIdlFile\n";
82 }
83 my $targetInterfaceName = fileparse(basename($targetIdlFile), ".idl");
84
85 my $idlFound = 0;
86 my @supplementedIdlFiles;
87 if ($supplementalDependencyFile) {
88     # The format of a supplemental dependency file:
89     #
90     # DOMWindow.idl P.idl Q.idl R.idl
91     # Document.idl S.idl
92     # Event.idl
93     # ...
94     #
95     # The above indicates that DOMWindow.idl is supplemented by P.idl, Q.idl and R.idl,
96     # Document.idl is supplemented by S.idl, and Event.idl is supplemented by no IDLs.
97     # The IDL that supplements another IDL (e.g. P.idl) never appears in the dependency file.
98     open FH, "< $supplementalDependencyFile" or die "Cannot open $supplementalDependencyFile\n";
99     while (my $line = <FH>) {
100         my ($idlFile, @followingIdlFiles) = split(/\s+/, $line);
101         if ($idlFile and basename($idlFile) eq basename($targetIdlFile)) {
102             $idlFound = 1;
103             @supplementedIdlFiles = sort @followingIdlFiles;
104         }
105     }
106     close FH;
107
108     # $additionalIdlFiles is list of IDL files which should not be included in
109     # DerivedSources*.cpp (i.e. they are not described in the supplemental
110     # dependency file) but should generate .h and .cpp files.
111     if (!$idlFound and $additionalIdlFiles) {
112         my @idlFiles = shellwords($additionalIdlFiles);
113         $idlFound = grep { $_ and basename($_) eq basename($targetIdlFile) } @idlFiles;
114     }
115
116     if (!$idlFound) {
117         my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, $preprocessor, $writeDependencies, $verbose);
118
119         # We generate empty .h and .cpp files just to tell build scripts that .h and .cpp files are created.
120         generateEmptyHeaderAndCpp($codeGen->FileNamePrefix(), $targetInterfaceName, $outputHeadersDirectory, $outputDirectory);
121         exit 0;
122     }
123 }
124
125 # Parse the target IDL file.
126 my $targetParser = IDLParser->new(!$verbose);
127 my $targetDocument = $targetParser->Parse($targetIdlFile, $defines, $preprocessor);
128
129 if ($idlAttributesFile) {
130     my $idlAttributes = loadIDLAttributes($idlAttributesFile);
131     checkIDLAttributes($idlAttributes, $targetDocument, basename($targetIdlFile));
132 }
133
134 foreach my $idlFile (@supplementedIdlFiles) {
135     next if $idlFile eq $targetIdlFile;
136
137     my $interfaceName = fileparse(basename($idlFile), ".idl");
138     my $parser = IDLParser->new(!$verbose);
139     my $document = $parser->Parse($idlFile, $defines, $preprocessor);
140
141     foreach my $interface (@{$document->interfaces}) {
142         if (!$interface->isPartial || $interface->name eq $targetInterfaceName) {
143             my $targetDataNode;
144             foreach my $interface (@{$targetDocument->interfaces}) {
145                 if ($interface->name eq $targetInterfaceName) {
146                     $targetDataNode = $interface;
147                     last;
148                 }
149             }
150             die "Not found an interface ${targetInterfaceName} in ${targetInterfaceName}.idl." unless defined $targetDataNode;
151
152             # Support for attributes of partial interfaces.
153             foreach my $attribute (@{$interface->attributes}) {
154                 # Record that this attribute is implemented by $interfaceName.
155                 $attribute->signature->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
156
157                 # Add interface-wide extended attributes to each attribute.
158                 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) {
159                     $attribute->signature->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
160                 }
161                 push(@{$targetDataNode->attributes}, $attribute);
162             }
163
164             # Support for methods of partial interfaces.
165             foreach my $function (@{$interface->functions}) {
166                 # Record that this method is implemented by $interfaceName.
167                 $function->signature->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
168
169                 # Add interface-wide extended attributes to each method.
170                 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) {
171                     $function->signature->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
172                 }
173                 push(@{$targetDataNode->functions}, $function);
174             }
175
176             # Support for constants of partial interfaces.
177             foreach my $constant (@{$interface->constants}) {
178                 # Record that this constant is implemented by $interfaceName.
179                 $constant->extendedAttributes->{"ImplementedBy"} = $interfaceName if $interface->isPartial;
180
181                 # Add interface-wide extended attributes to each constant.
182                 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) {
183                     $constant->extendedAttributes->{$extendedAttributeName} = $interface->extendedAttributes->{$extendedAttributeName};
184                 }
185                 push(@{$targetDataNode->constants}, $constant);
186             }
187         } else {
188             die "$idlFile is not a supplemental dependency of $targetIdlFile. There maybe a bug in the the supplemental dependency generator (preprocess-idls.pl).\n";
189         }
190     }
191 }
192
193 # Generate desired output for the target IDL file.
194 my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, $outputHeadersDirectory, $preprocessor, $writeDependencies, $verbose, $targetIdlFile);
195 $codeGen->ProcessDocument($targetDocument, $defines);
196
197 sub generateEmptyHeaderAndCpp
198 {
199     my ($prefix, $targetInterfaceName, $outputHeadersDirectory, $outputDirectory) = @_;
200
201     my $headerName = "${prefix}${targetInterfaceName}.h";
202     my $cppName = "${prefix}${targetInterfaceName}.cpp";
203     my $contents = "/*
204     This file is generated just to tell build scripts that $headerName and
205     $cppName are created for ${targetInterfaceName}.idl, and thus
206     prevent the build scripts from trying to generate $headerName and
207     $cppName at every build. This file must not be tried to compile.
208 */
209 ";
210     open FH, "> ${outputHeadersDirectory}/${headerName}" or die "Cannot open $headerName\n";
211     print FH $contents;
212     close FH;
213
214     open FH, "> ${outputDirectory}/${cppName}" or die "Cannot open $cppName\n";
215     print FH $contents;
216     close FH;
217 }
218
219 sub loadIDLAttributes
220 {
221     my $idlAttributesFile = shift;
222
223     my %idlAttributes;
224     open FH, "<", $idlAttributesFile or die "Couldn't open $idlAttributesFile: $!";
225     while (my $line = <FH>) {
226         chomp $line;
227         next if $line =~ /^\s*#/;
228         next if $line =~ /^\s*$/;
229
230         if ($line =~ /^\s*([^=\s]*)\s*=?\s*(.*)/) {
231             my $name = $1;
232             $idlAttributes{$name} = {};
233             if ($2) {
234                 foreach my $rightValue (split /\|/, $2) {
235                     $rightValue =~ s/^\s*|\s*$//g;
236                     $rightValue = "VALUE_IS_MISSING" unless $rightValue;
237                     $idlAttributes{$name}{$rightValue} = 1;
238                 }
239             } else {
240                 $idlAttributes{$name}{"VALUE_IS_MISSING"} = 1;
241             }
242         } else {
243             die "The format of " . basename($idlAttributesFile) . " is wrong: line $.\n";
244         }
245     }
246     close FH;
247
248     return \%idlAttributes;
249 }
250
251 sub checkIDLAttributes
252 {
253     my $idlAttributes = shift;
254     my $document = shift;
255     my $idlFile = shift;
256
257     foreach my $interface (@{$document->interfaces}) {
258         checkIfIDLAttributesExists($idlAttributes, $interface->extendedAttributes, $idlFile);
259
260         foreach my $attribute (@{$interface->attributes}) {
261             checkIfIDLAttributesExists($idlAttributes, $attribute->signature->extendedAttributes, $idlFile);
262         }
263
264         foreach my $function (@{$interface->functions}) {
265             checkIfIDLAttributesExists($idlAttributes, $function->signature->extendedAttributes, $idlFile);
266             foreach my $parameter (@{$function->parameters}) {
267                 checkIfIDLAttributesExists($idlAttributes, $parameter->extendedAttributes, $idlFile);
268             }
269         }
270     }
271 }
272
273 sub checkIfIDLAttributesExists
274 {
275     my $idlAttributes = shift;
276     my $extendedAttributes = shift;
277     my $idlFile = shift;
278
279     my $error;
280     OUTER: for my $name (keys %$extendedAttributes) {
281         if (!exists $idlAttributes->{$name}) {
282             $error = "Unknown IDL attribute [$name] is found at $idlFile.";
283             last OUTER;
284         }
285         if ($idlAttributes->{$name}{"*"}) {
286             next;
287         }
288         for my $rightValue (split /\s*[|&]\s*/, $extendedAttributes->{$name}) {
289             if (!exists $idlAttributes->{$name}{$rightValue}) {
290                 $error = "Unknown IDL attribute [$name=" . $extendedAttributes->{$name} . "] is found at $idlFile.";
291                 last OUTER;
292             }
293         }
294     }
295     if ($error) {
296         die "IDL ATTRIBUTE CHECKER ERROR: $error
297 If you want to add a new IDL attribute, you need to add it to WebCore/bindings/scripts/IDLAttributes.txt and add explanations to the WebKit IDL document (https://trac.webkit.org/wiki/WebKitIDL).
298 ";
299     }
300 }