preprocess-idls.pl 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  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. use strict;
  21. use File::Basename;
  22. use Getopt::Long;
  23. use Cwd;
  24. my $defines;
  25. my $preprocessor;
  26. my $idlFilesList;
  27. my $supplementalDependencyFile;
  28. my $windowConstructorsFile;
  29. my $workerContextConstructorsFile;
  30. my $supplementalMakefileDeps;
  31. GetOptions('defines=s' => \$defines,
  32. 'preprocessor=s' => \$preprocessor,
  33. 'idlFilesList=s' => \$idlFilesList,
  34. 'supplementalDependencyFile=s' => \$supplementalDependencyFile,
  35. 'windowConstructorsFile=s' => \$windowConstructorsFile,
  36. 'workerContextConstructorsFile=s' => \$workerContextConstructorsFile,
  37. 'supplementalMakefileDeps=s' => \$supplementalMakefileDeps);
  38. die('Must specify #define macros using --defines.') unless defined($defines);
  39. die('Must specify an output file using --supplementalDependencyFile.') unless defined($supplementalDependencyFile);
  40. die('Must specify an output file using --windowConstructorsFile.') unless defined($windowConstructorsFile);
  41. die('Must specify an output file using --workerContextConstructorsFile.') unless defined($workerContextConstructorsFile);
  42. die('Must specify the file listing all IDLs using --idlFilesList.') unless defined($idlFilesList);
  43. open FH, "< $idlFilesList" or die "Cannot open $idlFilesList\n";
  44. my @idlFiles = <FH>;
  45. chomp(@idlFiles);
  46. close FH;
  47. # Parse all IDL files.
  48. my %interfaceNameToIdlFile;
  49. my %idlFileToInterfaceName;
  50. my %supplementalDependencies;
  51. my %supplementals;
  52. my $windowConstructorsCode = "";
  53. my $workerContextConstructorsCode = "";
  54. # Get rid of duplicates in idlFiles array.
  55. my %idlFileHash = map { $_, 1 } @idlFiles;
  56. foreach my $idlFile (sort keys %idlFileHash) {
  57. my $fullPath = Cwd::realpath($idlFile);
  58. my $idlFileContents = getFileContents($fullPath);
  59. my $partialInterfaceName = getPartialInterfaceNameFromIDL($idlFileContents);
  60. if ($partialInterfaceName) {
  61. $supplementalDependencies{$fullPath} = $partialInterfaceName;
  62. next;
  63. }
  64. my $interfaceName = fileparse(basename($idlFile), ".idl");
  65. unless (isCallbackInterfaceFromIDL($idlFileContents)) {
  66. my $extendedAttributes = getInterfaceExtendedAttributesFromIDL($idlFileContents);
  67. unless ($extendedAttributes->{"NoInterfaceObject"}) {
  68. my $globalContext = $extendedAttributes->{"GlobalContext"} || "WindowOnly";
  69. my $attributeCode = GenerateConstructorAttribute($interfaceName, $extendedAttributes);
  70. $windowConstructorsCode .= $attributeCode unless $globalContext eq "WorkerOnly";
  71. $workerContextConstructorsCode .= $attributeCode unless $globalContext eq "WindowOnly"
  72. }
  73. }
  74. $interfaceNameToIdlFile{$interfaceName} = $fullPath;
  75. $idlFileToInterfaceName{$fullPath} = $interfaceName;
  76. $supplementals{$fullPath} = [];
  77. }
  78. # Generate DOMWindow Constructors partial interface.
  79. GeneratePartialInterface("DOMWindow", $windowConstructorsCode, $windowConstructorsFile);
  80. # Generate WorkerContext Constructors partial interface.
  81. GeneratePartialInterface("WorkerContext", $workerContextConstructorsCode, $workerContextConstructorsFile);
  82. # Resolves partial interfaces dependencies.
  83. foreach my $idlFile (keys %supplementalDependencies) {
  84. my $baseFile = $supplementalDependencies{$idlFile};
  85. my $targetIdlFile = $interfaceNameToIdlFile{$baseFile};
  86. push(@{$supplementals{$targetIdlFile}}, $idlFile);
  87. delete $supplementals{$idlFile};
  88. }
  89. # Outputs the dependency.
  90. # The format of a supplemental dependency file:
  91. #
  92. # DOMWindow.idl P.idl Q.idl R.idl
  93. # Document.idl S.idl
  94. # Event.idl
  95. # ...
  96. #
  97. # The above indicates that DOMWindow.idl is supplemented by P.idl, Q.idl and R.idl,
  98. # Document.idl is supplemented by S.idl, and Event.idl is supplemented by no IDLs.
  99. # The IDL that supplements another IDL (e.g. P.idl) never appears in the dependency file.
  100. my $dependencies = "";
  101. foreach my $idlFile (sort keys %supplementals) {
  102. $dependencies .= "$idlFile @{$supplementals{$idlFile}}\n";
  103. }
  104. WriteFileIfChanged($supplementalDependencyFile, $dependencies);
  105. if ($supplementalMakefileDeps) {
  106. my $makefileDeps = "";
  107. foreach my $idlFile (sort keys %supplementals) {
  108. my $basename = $idlFileToInterfaceName{$idlFile};
  109. my @dependencies = map { basename($_) } @{$supplementals{$idlFile}};
  110. $makefileDeps .= "JS${basename}.h: @{dependencies}\n";
  111. $makefileDeps .= "DOM${basename}.h: @{dependencies}\n";
  112. $makefileDeps .= "WebDOM${basename}.h: @{dependencies}\n";
  113. foreach my $dependency (@dependencies) {
  114. $makefileDeps .= "${dependency}:\n";
  115. }
  116. }
  117. WriteFileIfChanged($supplementalMakefileDeps, $makefileDeps);
  118. }
  119. sub WriteFileIfChanged
  120. {
  121. my $fileName = shift;
  122. my $contents = shift;
  123. if (-f $fileName) {
  124. open FH, "<", $fileName or die "Couldn't open $fileName: $!\n";
  125. my @lines = <FH>;
  126. my $oldContents = join "", @lines;
  127. close FH;
  128. return if $contents eq $oldContents;
  129. }
  130. open FH, ">", $fileName or die "Couldn't open $fileName: $!\n";
  131. print FH $contents;
  132. close FH;
  133. }
  134. sub GeneratePartialInterface
  135. {
  136. my $interfaceName = shift;
  137. my $attributesCode = shift;
  138. my $destinationFile = shift;
  139. my $contents = "partial interface ${interfaceName} {\n$attributesCode};\n";
  140. WriteFileIfChanged($destinationFile, $contents);
  141. my $fullPath = Cwd::realpath($destinationFile);
  142. $supplementalDependencies{$fullPath} = $interfaceName if $interfaceNameToIdlFile{$interfaceName};
  143. }
  144. sub GenerateConstructorAttribute
  145. {
  146. my $interfaceName = shift;
  147. my $extendedAttributes = shift;
  148. my $code = " ";
  149. my @extendedAttributesList;
  150. foreach my $attributeName (keys %{$extendedAttributes}) {
  151. next unless ($attributeName eq "Conditional" || $attributeName eq "EnabledAtRuntime" || $attributeName eq "EnabledBySetting");
  152. my $extendedAttribute = $attributeName;
  153. $extendedAttribute .= "=" . $extendedAttributes->{$attributeName} unless $extendedAttributes->{$attributeName} eq "VALUE_IS_MISSING";
  154. push(@extendedAttributesList, $extendedAttribute);
  155. }
  156. $code .= "[" . join(', ', @extendedAttributesList) . "] " if @extendedAttributesList;
  157. my $originalInterfaceName = $interfaceName;
  158. $interfaceName = $extendedAttributes->{"InterfaceName"} if $extendedAttributes->{"InterfaceName"};
  159. $code .= "attribute " . $originalInterfaceName . "Constructor $interfaceName;\n";
  160. # In addition to the regular property, for every [NamedConstructor] extended attribute on an interface,
  161. # a corresponding property MUST exist on the ECMAScript global object.
  162. if ($extendedAttributes->{"NamedConstructor"}) {
  163. my $constructorName = $extendedAttributes->{"NamedConstructor"};
  164. $constructorName =~ s/\(.*//g; # Extract function name.
  165. $code .= " ";
  166. $code .= "[" . join(', ', @extendedAttributesList) . "] " if @extendedAttributesList;
  167. $code .= "attribute " . $originalInterfaceName . "NamedConstructor $constructorName;\n";
  168. }
  169. return $code;
  170. }
  171. sub getFileContents
  172. {
  173. my $idlFile = shift;
  174. open FILE, "<", $idlFile;
  175. my @lines = <FILE>;
  176. close FILE;
  177. # Filter out preprocessor lines.
  178. @lines = grep(!/^\s*#/, @lines);
  179. return join('', @lines);
  180. }
  181. sub getPartialInterfaceNameFromIDL
  182. {
  183. my $fileContents = shift;
  184. if ($fileContents =~ /partial\s+interface\s+(\w+)/gs) {
  185. return $1;
  186. }
  187. }
  188. sub isCallbackInterfaceFromIDL
  189. {
  190. my $fileContents = shift;
  191. return ($fileContents =~ /callback\s+interface\s+\w+/gs);
  192. }
  193. sub trim
  194. {
  195. my $string = shift;
  196. $string =~ s/^\s+|\s+$//g;
  197. return $string;
  198. }
  199. sub getInterfaceExtendedAttributesFromIDL
  200. {
  201. my $fileContents = shift;
  202. my $extendedAttributes = {};
  203. if ($fileContents =~ /\[(.*)\]\s+(interface|exception)\s+(\w+)/gs) {
  204. my @parts = split(',', $1);
  205. foreach my $part (@parts) {
  206. my @keyValue = split('=', $part);
  207. my $key = trim($keyValue[0]);
  208. next unless length($key);
  209. my $value = "VALUE_IS_MISSING";
  210. $value = trim($keyValue[1]) if @keyValue > 1;
  211. $extendedAttributes->{$key} = $value;
  212. }
  213. }
  214. return $extendedAttributes;
  215. }