Add support for [NoInterfaceObject] Web IDL extended attribute
[WebKit-https.git] / Source / WebCore / bindings / scripts / preprocess-idls.pl
1 #!/usr/bin/perl -w
2 #
3 # Copyright (C) 2011 Google Inc.  All rights reserved.
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Library General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Library General Public License for more details.
14 #
15 # You should have received a copy of the GNU Library General Public License
16 # along with this library; see the file COPYING.LIB.  If not, write to
17 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 # Boston, MA 02110-1301, USA.
19 #
20
21 use strict;
22
23 use File::Basename;
24 use Getopt::Long;
25 use Cwd;
26
27 my $defines;
28 my $preprocessor;
29 my $idlFilesList;
30 my $supplementalDependencyFile;
31 my $windowConstructorsFile;
32 my $supplementalMakefileDeps;
33
34 GetOptions('defines=s' => \$defines,
35            'preprocessor=s' => \$preprocessor,
36            'idlFilesList=s' => \$idlFilesList,
37            'supplementalDependencyFile=s' => \$supplementalDependencyFile,
38            'windowConstructorsFile=s' => \$windowConstructorsFile,
39            'supplementalMakefileDeps=s' => \$supplementalMakefileDeps);
40
41 die('Must specify #define macros using --defines.') unless defined($defines);
42 die('Must specify an output file using --supplementalDependencyFile.') unless defined($supplementalDependencyFile);
43 die('Must specify an output file using --windowConstructorsFile.') unless defined($windowConstructorsFile);
44 die('Must specify the file listing all IDLs using --idlFilesList.') unless defined($idlFilesList);
45
46 open FH, "< $idlFilesList" or die "Cannot open $idlFilesList\n";
47 my @idlFiles = <FH>;
48 chomp(@idlFiles);
49 close FH;
50
51 # Parse all IDL files.
52 my %interfaceNameToIdlFile;
53 my %idlFileToInterfaceName;
54 my %supplementalDependencies;
55 my %supplementals;
56 my $constructorAttributesCode = "";
57 # Get rid of duplicates in idlFiles array.
58 my %idlFileHash = map { $_, 1 } @idlFiles;
59 foreach my $idlFile (keys %idlFileHash) {
60     my $fullPath = Cwd::realpath($idlFile);
61     my $idlFileContents = getFileContents($fullPath);
62     my $partialInterfaceName = getPartialInterfaceNameFromIDL($idlFileContents);
63     if ($partialInterfaceName) {
64         $supplementalDependencies{$fullPath} = $partialInterfaceName;
65         next;
66     }
67     my $interfaceName = fileparse(basename($idlFile), ".idl");
68     unless (isCallbackInterfaceFromIDL($idlFileContents)) {
69         my $extendedAttributes = getInterfaceExtendedAttributesFromIDL($idlFileContents);
70         unless ($extendedAttributes->{"NoInterfaceObject"}) {
71             $constructorAttributesCode .= GenerateConstructorAttribute($interfaceName, $extendedAttributes);
72         }
73     }
74     $interfaceNameToIdlFile{$interfaceName} = $fullPath;
75     $idlFileToInterfaceName{$fullPath} = $interfaceName;
76     $supplementals{$fullPath} = [];
77 }
78
79 # Generate DOMWindow Constructors partial interface.
80 open PARTIAL_WINDOW_FH, "> $windowConstructorsFile" or die "Cannot open $windowConstructorsFile\n";
81 print PARTIAL_WINDOW_FH "partial interface DOMWindow {\n";
82 print PARTIAL_WINDOW_FH $constructorAttributesCode;
83 print PARTIAL_WINDOW_FH "};\n";
84 close PARTIAL_WINDOW_FH;
85 my $fullPath = Cwd::realpath($windowConstructorsFile);
86 $supplementalDependencies{$fullPath} = "DOMWindow" if $interfaceNameToIdlFile{"DOMWindow"};
87
88 # Resolves partial interfaces dependencies.
89 foreach my $idlFile (keys %supplementalDependencies) {
90     my $baseFile = $supplementalDependencies{$idlFile};
91     my $targetIdlFile = $interfaceNameToIdlFile{$baseFile};
92     push(@{$supplementals{$targetIdlFile}}, $idlFile);
93     delete $supplementals{$idlFile};
94 }
95
96 # Outputs the dependency.
97 # The format of a supplemental dependency file:
98 #
99 # DOMWindow.idl P.idl Q.idl R.idl
100 # Document.idl S.idl
101 # Event.idl
102 # ...
103 #
104 # The above indicates that DOMWindow.idl is supplemented by P.idl, Q.idl and R.idl,
105 # Document.idl is supplemented by S.idl, and Event.idl is supplemented by no IDLs.
106 # The IDL that supplements another IDL (e.g. P.idl) never appears in the dependency file.
107
108 open FH, "> $supplementalDependencyFile" or die "Cannot open $supplementalDependencyFile\n";
109
110 foreach my $idlFile (sort keys %supplementals) {
111     print FH $idlFile, " @{$supplementals{$idlFile}}\n";
112 }
113 close FH;
114
115
116 if ($supplementalMakefileDeps) {
117     open MAKE_FH, "> $supplementalMakefileDeps" or die "Cannot open $supplementalMakefileDeps\n";
118     my @all_dependencies = [];
119     foreach my $idlFile (sort keys %supplementals) {
120         my $basename = $idlFileToInterfaceName{$idlFile};
121
122         my @dependencies = map { basename($_) } @{$supplementals{$idlFile}};
123
124         print MAKE_FH "JS${basename}.h: @{dependencies}\n";
125         print MAKE_FH "DOM${basename}.h: @{dependencies}\n";
126         print MAKE_FH "WebDOM${basename}.h: @{dependencies}\n";
127         foreach my $dependency (@dependencies) {
128             print MAKE_FH "${dependency}:\n";
129         }
130     }
131
132     close MAKE_FH;
133 }
134
135 sub GenerateConstructorAttribute
136 {
137     my $interfaceName = shift;
138     my $extendedAttributes = shift;
139
140     my $code = "    ";
141     my @extendedAttributesList;
142     foreach my $attributeName (keys %{$extendedAttributes}) {
143       next unless ($attributeName eq "Conditional" || $attributeName eq "EnabledAtRuntime" || $attributeName eq "EnabledPerContext");
144       my $extendedAttribute = $attributeName;
145       $extendedAttribute .= "=" . $extendedAttributes->{$attributeName} unless $extendedAttributes->{$attributeName} eq "VALUE_IS_MISSING";
146       push(@extendedAttributesList, $extendedAttribute);
147     }
148     $code .= "[" . join(', ', @extendedAttributesList) . "] " if @extendedAttributesList;
149
150     my $originalInterfaceName = $interfaceName;
151     $interfaceName = $extendedAttributes->{"InterfaceName"} if $extendedAttributes->{"InterfaceName"};
152     $code .= "attribute " . $originalInterfaceName . "Constructor $interfaceName;\n";
153
154     # In addition to the regular property, for every [NamedConstructor] extended attribute on an interface,
155     # a corresponding property MUST exist on the ECMAScript global object.
156     if ($extendedAttributes->{"NamedConstructor"}) {
157         my $constructorName = $extendedAttributes->{"NamedConstructor"};
158         $constructorName =~ s/\(.*//g; # Extract function name.
159         $code .= "    ";
160         $code .= "[" . join(', ', @extendedAttributesList) . "] " if @extendedAttributesList;
161         $code .= "attribute " . $originalInterfaceName . "ConstructorConstructor $constructorName;\n";
162     }
163     return $code;
164 }
165
166 sub getFileContents
167 {
168     my $idlFile = shift;
169
170     open FILE, "<", $idlFile;
171     my @lines = <FILE>;
172     close FILE;
173
174     # Filter out preprocessor lines.
175     @lines = grep(!/^\s*#/, @lines);
176
177     return join('', @lines);
178 }
179
180 sub getPartialInterfaceNameFromIDL
181 {
182     my $fileContents = shift;
183
184     if ($fileContents =~ /partial\s+interface\s+(\w+)/gs) {
185         return $1;
186     }
187 }
188
189 sub isCallbackInterfaceFromIDL
190 {
191     my $fileContents = shift;
192     return ($fileContents =~ /callback\s+interface\s+\w+/gs);
193 }
194
195 sub trim
196 {
197     my $string = shift;
198     $string =~ s/^\s+|\s+$//g;
199     return $string;
200 }
201
202 sub getInterfaceExtendedAttributesFromIDL
203 {
204     my $fileContents = shift;
205
206     my $extendedAttributes = {};
207
208     if ($fileContents =~ /\[(.*)\]\s+(interface|exception)\s+(\w+)/gs) {
209         my @parts = split(',', $1);
210         foreach my $part (@parts) {
211             my @keyValue = split('=', $part);
212             my $key = trim($keyValue[0]);
213             next unless length($key);
214             my $value = "VALUE_IS_MISSING";
215             $value = trim($keyValue[1]) if @keyValue > 1;
216             $extendedAttributes->{$key} = $value;
217         }
218     }
219
220     return $extendedAttributes;
221 }