Title: [266687] trunk
Revision
266687
Author
[email protected]
Date
2020-09-06 17:20:01 -0700 (Sun, 06 Sep 2020)

Log Message

[WebIDL] Add mode to preprocess-idls.pl to validate fast regex based scanner with the normal IDL parser
https://bugs.webkit.org/show_bug.cgi?id=216231

Reviewed by Darin Adler.

Source/WebCore:

To aid tracking down mistakes in the fast regex based scanner in preprocess-idls.pl, this
adds a validation mode to the script which checks the results against what the normal, much
slower, IDL parser gets. In building it, it caught that we were not creating a dependency on
RTCRtpCodingParameters.idl for dictionaries that derived from it because it was missing from
DerivedSources.make/CMakeLists.txt, which would have manifested in confusing build errors
in some cases.

* CMakeLists.txt:
* DerivedSources.make:
* bindings/scripts/generate-bindings-all.pl:
Add missing RTCRtpCodingParameters.idl and update invocation of preprocess-idls.pl to
pass in idlAttributesFile, which the parser needs (it is not read when not validating).

* bindings/scripts/test/SupplementalDependencies.dep:
Updated to include missing dictionary dependencies.

* bindings/scripts/preprocess-idls.pl:
(GeneratePartialInterface):
(processIDL):
(getPartialNamesFromIDL):
(getIncludedInterfacesFromIDL):
(isCallbackInterfaceFromIDL):
(isMixinInterfaceFromIDL):
(containsIterableInterfaceFromIDL):
(containsInterfaceOrCallbackInterfaceFromIDL):
(containsInterfaceWithConstantsFromIDL):
(getInterfaceExtendedAttributesFromIDL):
(getUndefinedBaseDictionariesFromIDL):
(shouldExposeInterface):
(getFileContents): Deleted.
(interfaceIsIterable): Deleted.
(containsInterfaceFromIDL): Deleted.
(interfaceHasConstantAttribute): Deleted.
(updateDictionaryDependencies): Deleted.
- Allow enabling a validation mode via the $validateAgainstParser variable which parses each
  IDL with the normal IDL parser and compares results.
- Updates a bunch of naming to be more clear about which variables contain file names vs. file
  paths.
- Renames functions to use more consistent naming.
- Fixes bug in dictionary dependency analysis that silently ignored dependencies that weren't
  in the file list.

Tools:

* Scripts/webkitpy/bindings/main.py:
(BindingsTests.generate_supplemental_dependency):
Update for rename from idlFilesList to idlFileNamesList and to pass the idlAttributesFile argument.

Modified Paths

Diff

Modified: trunk/Source/WebCore/CMakeLists.txt (266686 => 266687)


--- trunk/Source/WebCore/CMakeLists.txt	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Source/WebCore/CMakeLists.txt	2020-09-07 00:20:01 UTC (rev 266687)
@@ -377,6 +377,7 @@
     Modules/mediastream/RTCRtpCapabilities.idl
     Modules/mediastream/RTCRtpCodecCapability.idl
     Modules/mediastream/RTCRtpCodecParameters.idl
+    Modules/mediastream/RTCRtpCodingParameters.idl
     Modules/mediastream/RTCRtpContributingSource.idl
     Modules/mediastream/RTCRtpEncodingParameters.idl
     Modules/mediastream/RTCRtpFecParameters.idl

Modified: trunk/Source/WebCore/ChangeLog (266686 => 266687)


--- trunk/Source/WebCore/ChangeLog	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Source/WebCore/ChangeLog	2020-09-07 00:20:01 UTC (rev 266687)
@@ -1,3 +1,52 @@
+2020-09-06  Sam Weinig  <[email protected]>
+
+        [WebIDL] Add mode to preprocess-idls.pl to validate fast regex based scanner with the normal IDL parser
+        https://bugs.webkit.org/show_bug.cgi?id=216231
+
+        Reviewed by Darin Adler.
+
+        To aid tracking down mistakes in the fast regex based scanner in preprocess-idls.pl, this
+        adds a validation mode to the script which checks the results against what the normal, much
+        slower, IDL parser gets. In building it, it caught that we were not creating a dependency on
+        RTCRtpCodingParameters.idl for dictionaries that derived from it because it was missing from
+        DerivedSources.make/CMakeLists.txt, which would have manifested in confusing build errors
+        in some cases.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * bindings/scripts/generate-bindings-all.pl:
+        Add missing RTCRtpCodingParameters.idl and update invocation of preprocess-idls.pl to 
+        pass in idlAttributesFile, which the parser needs (it is not read when not validating).
+
+        * bindings/scripts/test/SupplementalDependencies.dep:
+        Updated to include missing dictionary dependencies.
+
+        * bindings/scripts/preprocess-idls.pl:
+        (GeneratePartialInterface):
+        (processIDL):
+        (getPartialNamesFromIDL):
+        (getIncludedInterfacesFromIDL):
+        (isCallbackInterfaceFromIDL):
+        (isMixinInterfaceFromIDL):
+        (containsIterableInterfaceFromIDL):
+        (containsInterfaceOrCallbackInterfaceFromIDL):
+        (containsInterfaceWithConstantsFromIDL):
+        (getInterfaceExtendedAttributesFromIDL):
+        (getUndefinedBaseDictionariesFromIDL):
+        (shouldExposeInterface):
+        (getFileContents): Deleted.
+        (interfaceIsIterable): Deleted.
+        (containsInterfaceFromIDL): Deleted.
+        (interfaceHasConstantAttribute): Deleted.
+        (updateDictionaryDependencies): Deleted.
+        - Allow enabling a validation mode via the $validateAgainstParser variable which parses each
+          IDL with the normal IDL parser and compares results. 
+        - Updates a bunch of naming to be more clear about which variables contain file names vs. file
+          paths.
+        - Renames functions to use more consistent naming.
+        - Fixes bug in dictionary dependency analysis that silently ignored dependencies that weren't
+          in the file list.
+
 2020-09-06  Myles C. Maxfield  <[email protected]>
 
         Remove all non-web-exposed uses of ENABLE(VARIATION_FONTS)

Modified: trunk/Source/WebCore/DerivedSources.make (266686 => 266687)


--- trunk/Source/WebCore/DerivedSources.make	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Source/WebCore/DerivedSources.make	2020-09-07 00:20:01 UTC (rev 266687)
@@ -306,6 +306,7 @@
     $(WebCore)/Modules/mediastream/RTCRtpCapabilities.idl \
     $(WebCore)/Modules/mediastream/RTCRtpCodecCapability.idl \
     $(WebCore)/Modules/mediastream/RTCRtpCodecParameters.idl \
+    $(WebCore)/Modules/mediastream/RTCRtpCodingParameters.idl \
     $(WebCore)/Modules/mediastream/RTCRtpContributingSource.idl \
     $(WebCore)/Modules/mediastream/RTCRtpEncodingParameters.idl \
     $(WebCore)/Modules/mediastream/RTCRtpFecParameters.idl \
@@ -1738,9 +1739,9 @@
 #
 IDL_INTERMEDIATE_PATTERNS = $(subst .,%,$(IDL_INTERMEDIATE_FILES))
 
-$(IDL_INTERMEDIATE_PATTERNS) : $(PREPROCESS_IDLS_SCRIPTS) $(JS_BINDING_IDLS) $(FEATURE_AND_PLATFORM_DEFINE_DEPENDENCIES) DerivedSources.make $(FEATURE_AND_PLATFORM_DEFINE_DEPENDENCIES)
+$(IDL_INTERMEDIATE_PATTERNS) : $(PREPROCESS_IDLS_SCRIPTS) $(IDL_ATTRIBUTES_FILE) $(JS_BINDING_IDLS) $(FEATURE_AND_PLATFORM_DEFINE_DEPENDENCIES) DerivedSources.make $(FEATURE_AND_PLATFORM_DEFINE_DEPENDENCIES)
 	$(foreach f,$(JS_BINDING_IDLS),@echo $(f)>>$(IDL_FILES_TMP)$(NL))
-	$(PERL) $(WebCore)/bindings/scripts/preprocess-idls.pl --defines "$(FEATURE_AND_PLATFORM_DEFINES) LANGUAGE_JAVASCRIPT" --idlFilesList $(IDL_FILES_TMP) --supplementalDependencyFile $(SUPPLEMENTAL_DEPENDENCY_FILE) --isoSubspacesHeaderFile $(ISO_SUBSPACES_HEADER_FILE) --windowConstructorsFile $(WINDOW_CONSTRUCTORS_FILE) --workerGlobalScopeConstructorsFile $(WORKERGLOBALSCOPE_CONSTRUCTORS_FILE) --dedicatedWorkerGlobalScopeConstructorsFile $(DEDICATEDWORKERGLOBALSCOPE_CONSTRUCTORS_FILE) --serviceWorkerGlobalScopeConstructorsFile $(SERVICEWORKERGLOBALSCOPE_CONSTRUCTORS_FILE) --workletGlobalScopeConstructorsFile $(WORKLETGLOBALSCOPE_CONSTRUCTORS_FILE) --paintWorkletGlobalScopeConstructorsFile $(PAINTWORKLETGLOBALSCOPE_CONSTRUCTORS_FILE) --supplementalMakefileDeps $(SUPPLEMENTAL_MAKEFILE_DEPS)
+	$(PERL) $(WebCore)/bindings/scripts/preprocess-idls.pl --defines "$(FEATURE_AND_PLATFORM_DEFINES) LANGUAGE_JAVASCRIPT" --idlFileNamesList $(IDL_FILES_TMP) --idlAttributesFile $(IDL_ATTRIBUTES_FILE) --supplementalDependencyFile $(SUPPLEMENTAL_DEPENDENCY_FILE) --isoSubspacesHeaderFile $(ISO_SUBSPACES_HEADER_FILE) --windowConstructorsFile $(WINDOW_CONSTRUCTORS_FILE) --workerGlobalScopeConstructorsFile $(WORKERGLOBALSCOPE_CONSTRUCTORS_FILE) --dedicatedWorkerGlobalScopeConstructorsFile $(DEDICATEDWORKERGLOBALSCOPE_CONSTRUCTORS_FILE) --serviceWorkerGlobalScopeConstructorsFile $(SERVICEWORKERGLOBALSCOPE_CONSTRUCTORS_FILE) --workletGlobalScopeConstructorsFile $(WORKLETGLOBALSCOPE_CONSTRUCTORS_FILE) --paintWorkletGlobalScopeConstructorsFile $(PAINTWORKLETGLOBALSCOPE_CONSTRUCTORS_FILE) --supplementalMakefileDeps $(SUPPLEMENTAL_MAKEFILE_DEPS)
 	$(DELETE) $(IDL_FILES_TMP)
 
 JS%.cpp JS%.h : %.idl $(JS_BINDINGS_SCRIPTS) $(IDL_ATTRIBUTES_FILE) $(IDL_INTERMEDIATE_FILES) $(FEATURE_AND_PLATFORM_DEFINE_DEPENDENCIES)

Modified: trunk/Source/WebCore/bindings/scripts/generate-bindings-all.pl (266686 => 266687)


--- trunk/Source/WebCore/bindings/scripts/generate-bindings-all.pl	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Source/WebCore/bindings/scripts/generate-bindings-all.pl	2020-09-07 00:20:01 UTC (rev 266687)
@@ -85,8 +85,9 @@
         readSupplementalDependencyFile($supplementalDependencyFile, \%oldSupplements) if -e $supplementalDependencyFile;
         my @args = (File::Spec->catfile($scriptDir, 'preprocess-idls.pl'),
                     '--defines', $defines,
-                    '--idlFilesList', $ppIDLFilesList,
+                    '--idlFileNamesList', $ppIDLFilesList,
                     '--supplementalDependencyFile', $supplementalDependencyFile,
+                    '--idlAttributesFile', $idlAttributesFile,
                     @ppExtraArgs);
         printProgress("Preprocess IDL");
         executeCommand($perl, @args) == 0 or die;

Modified: trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl (266686 => 266687)


--- trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Source/WebCore/bindings/scripts/preprocess-idls.pl	2020-09-07 00:20:01 UTC (rev 266687)
@@ -23,14 +23,20 @@
 use FindBin;
 use lib $FindBin::Bin;
 
+use English;
 use File::Basename;
 use Getopt::Long;
 use Cwd;
 use Config;
+use Class::Struct;
+use JSON::PP;
+use Data::Dumper;
 
+use IDLParser;
+
 my $defines;
 my $preprocessor;
-my $idlFilesList;
+my $idlFileNamesList;
 my $testGlobalContextName;
 my $supplementalDependencyFile;
 my $isoSubspacesHeaderFile;
@@ -42,10 +48,16 @@
 my $paintWorkletGlobalScopeConstructorsFile;
 my $testGlobalScopeConstructorsFile;
 my $supplementalMakefileDeps;
+my $idlAttributesFile;
 
+# Toggle this to validate that the fast regular _expression_ based "parsing" used
+# in this file produces the same results as the slower results produced by the
+# complete IDLParser.
+my $validateAgainstParser = 0;
+
 GetOptions('defines=s' => \$defines,
            'preprocessor=s' => \$preprocessor,
-           'idlFilesList=s' => \$idlFilesList,
+           'idlFileNamesList=s' => \$idlFileNamesList,
            'testGlobalContextName=s' => \$testGlobalContextName,
            'supplementalDependencyFile=s' => \$supplementalDependencyFile,
            'isoSubspacesHeaderFile=s' => \$isoSubspacesHeaderFile,
@@ -56,7 +68,9 @@
            'workletGlobalScopeConstructorsFile=s' => \$workletGlobalScopeConstructorsFile,
            'paintWorkletGlobalScopeConstructorsFile=s' => \$paintWorkletGlobalScopeConstructorsFile,
            'testGlobalScopeConstructorsFile=s' => \$testGlobalScopeConstructorsFile,
-           'supplementalMakefileDeps=s' => \$supplementalMakefileDeps);
+           'supplementalMakefileDeps=s' => \$supplementalMakefileDeps,
+           'idlAttributesFile=s' => \$idlAttributesFile,
+           'validateAgainstParser' => \$validateAgainstParser);
 
 die('Must specify #define macros using --defines.') unless defined($defines);
 die('Must specify an output file using --supplementalDependencyFile.') unless defined($supplementalDependencyFile);
@@ -67,7 +81,8 @@
 die('Must specify an output file using --workletGlobalScopeConstructorsFile.') unless defined($workletGlobalScopeConstructorsFile);
 die('Must specify an output file using --paintWorkletGlobalScopeConstructorsFile.') unless defined($paintWorkletGlobalScopeConstructorsFile);
 die('Must specify an output file using --testGlobalScopeConstructorsFile.') unless defined($testGlobalScopeConstructorsFile) || !defined($testGlobalContextName);
-die('Must specify the file listing all IDLs using --idlFilesList.') unless defined($idlFilesList);
+die('Must specify the file listing all IDLs using --idlFileNamesList.') unless defined($idlFileNamesList);
+die('Must specify IDL attributes file using --idlAttributesFile.') unless defined($idlAttributesFile);
 
 $supplementalDependencyFile = CygwinPathIfNeeded($supplementalDependencyFile);
 $isoSubspacesHeaderFile = CygwinPathIfNeeded($isoSubspacesHeaderFile);
@@ -79,13 +94,35 @@
 $paintWorkletGlobalScopeConstructorsFile = CygwinPathIfNeeded($paintWorkletGlobalScopeConstructorsFile);
 $supplementalMakefileDeps = CygwinPathIfNeeded($supplementalMakefileDeps) if defined($supplementalMakefileDeps);
 
-my @idlFiles;
-open(my $fh, '<', $idlFilesList) or die "Cannot open $idlFilesList";
-@idlFiles = map { CygwinPathIfNeeded(s/\r?\n?$//r) } <$fh>;
+my @idlFileNames;
+open(my $fh, '<', $idlFileNamesList) or die "Cannot open $idlFileNamesList";
+@idlFileNames = map { CygwinPathIfNeeded(s/\r?\n?$//r) } <$fh>;
 close($fh) or die;
 
-my %interfaceNameToIdlFile;
-my %idlFileToInterfaceName;
+my $idlAttributes;
+if ($validateAgainstParser) {
+    my $input;
+    {
+        local $INPUT_RECORD_SEPARATOR;
+        open(JSON, "<", $idlAttributesFile) or die "Couldn't open $idlAttributesFile: $!";
+        $input = <JSON>;
+        close(JSON);
+    }
+
+    my $jsonDecoder = JSON::PP->new->utf8;
+    my $jsonHashRef = $jsonDecoder->decode($input);
+    $idlAttributes = $jsonHashRef->{attributes};
+}
+
+struct( IDLFile => {
+    fileName => '$',
+    fileContents => '$',
+    primaryDeclarationName => '$',
+    parsedDocument => '$'
+});
+
+my %interfaceNameToIdlFilePath;
+my %idlFilePathToInterfaceName;
 my %supplementalDependencies;
 my %dictionaryDependencies;
 my %supplementals;
@@ -112,23 +149,25 @@
     DOMIsoSubspaces() = default;
 END
 
-# Get rid of duplicates in idlFiles array.
-my %idlFileHash = map { $_, 1 } @idlFiles;
+# Get rid of duplicates in idlFileNames array.
+my %idlFileNameHash = map { $_, 1 } @idlFileNames;
 
-# Populate $idlFileToInterfaceName and $interfaceNameToIdlFile.
-foreach my $idlFile (sort keys %idlFileHash) {
-    my $fullPath = Cwd::realpath($idlFile);
-    my $interfaceName = fileparse(basename($idlFile), ".idl");
-    $idlFileToInterfaceName{$fullPath} = $interfaceName;
-    $interfaceNameToIdlFile{$interfaceName} = $fullPath;
+# Populate $idlFilePathToInterfaceName and $interfaceNameToIdlFilePath.
+foreach my $idlFileName (sort keys %idlFileNameHash) {
+    my $fullPath = Cwd::realpath($idlFileName);
+    my $interfaceName = fileparse(basename($idlFileName), ".idl");
+    $idlFilePathToInterfaceName{$fullPath} = $interfaceName;
+    $interfaceNameToIdlFilePath{$interfaceName} = $fullPath;
 }
 
 # Parse all IDL files.
-foreach my $idlFile (sort keys %idlFileHash) {
-    my $fullPath = Cwd::realpath($idlFile);
-    my $idlFileContents = getFileContents($fullPath);
+foreach my $idlFileName (sort keys %idlFileNameHash) {
+    my $fullPath = Cwd::realpath($idlFileName);
+    
+    my $idlFile = processIDL($idlFileName, $fullPath);
+
     # Handle partial names.
-    my $partialNames = getPartialNamesFromIDL($idlFileContents);
+    my $partialNames = getPartialNamesFromIDL($idlFile);
     if (@{$partialNames}) {
         $supplementalDependencies{$fullPath} = $partialNames;
         next;
@@ -136,31 +175,34 @@
 
     $supplementals{$fullPath} = [];
 
-    updateDictionaryDependencies($idlFileContents, $idlFile);
+    my $baseDictionaries = getUndefinedBaseDictionariesFromIDL($idlFile);
+    if (@{$baseDictionaries}) {
+        $dictionaryDependencies{$idlFile->primaryDeclarationName} = (join(".idl ", @{$baseDictionaries}) . ".idl");
+    }
 
     # Skip if the IDL file does not contain an interface or a callback interface.
     # The IDL may contain a dictionary.
-    next unless containsInterfaceFromIDL($idlFileContents);
+    next unless containsInterfaceOrCallbackInterfaceFromIDL($idlFile);
 
-    my $interfaceName = fileparse(basename($idlFile), ".idl");
+    my $interfaceName = $idlFile->primaryDeclarationName;
     # Handle include statements.
-    my $includedInterfaces = getIncludedInterfacesFromIDL($idlFileContents, $interfaceName);
+    my $includedInterfaces = getIncludedInterfacesFromIDL($idlFile, $interfaceName);
     foreach my $includedInterface (@{$includedInterfaces}) {
-        my $includedIdlFile = $interfaceNameToIdlFile{$includedInterface};
-        die "Could not find a the IDL file where the following included interface is defined: $includedInterface" unless $includedIdlFile;
-        if ($supplementalDependencies{$includedIdlFile}) {
-            push(@{$supplementalDependencies{$includedIdlFile}}, $interfaceName);
+        my $includedIdlFilePath = $interfaceNameToIdlFilePath{$includedInterface};
+        die "Could not find a the IDL file where the following included interface is defined: $includedInterface" unless $includedIdlFilePath;
+        if ($supplementalDependencies{$includedIdlFilePath}) {
+            push(@{$supplementalDependencies{$includedIdlFilePath}}, $interfaceName);
         } else {
-            $supplementalDependencies{$includedIdlFile} = [$interfaceName];
+            $supplementalDependencies{$includedIdlFilePath} = [$interfaceName];
         }
     }
 
-    next if isMixinInterfaceFromIDL($idlFileContents);
+    next if isMixinInterfaceFromIDL($idlFile);
 
-    my $isCallbackInterface = isCallbackInterfaceFromIDL($idlFileContents);
+    my $isCallbackInterface = isCallbackInterfaceFromIDL($idlFile);
     if (!$isCallbackInterface) {
         $isoSubspacesHeaderCode .= "    std::unique_ptr<JSC::IsoSubspace> m_subspaceFor${interfaceName};\n";
-        if (interfaceIsIterable($idlFileContents)) {
+        if (containsIterableInterfaceFromIDL($idlFile)) {
             $isoSubspacesHeaderCode .= "    std::unique_ptr<JSC::IsoSubspace> m_subspaceFor${interfaceName}Iterator;\n";
         }
     }
@@ -170,9 +212,9 @@
     # - is a non-callback interface that is not declared with the [LegacyNoInterfaceObject] extended attribute, a corresponding
     #   property must exist on the ECMAScript environment's global object.
     # See https://heycam.github.io/webidl/#es-interfaces
-    my $extendedAttributes = getInterfaceExtendedAttributesFromIDL($idlFileContents);
+    my $extendedAttributes = getInterfaceExtendedAttributesFromIDL($idlFile);
     if (shouldExposeInterface($extendedAttributes)) {
-        if (!$isCallbackInterface || interfaceHasConstantAttribute($idlFileContents)) {
+        if (!$isCallbackInterface || containsInterfaceWithConstantsFromIDL($idlFile)) {
             my $exposedAttribute = $extendedAttributes->{"Exposed"} || $testGlobalContextName || "Window";
             $exposedAttribute = substr($exposedAttribute, 1, -1) if substr($exposedAttribute, 0, 1) eq "(";
             my @globalContexts = split(",", $exposedAttribute);
@@ -193,7 +235,7 @@
                 } elsif ($globalContext eq $testGlobalContextName) {
                     $testGlobalScopeConstructorsCode .= $attributeCode;
                 } else {
-                    die "Unsupported global context '$globalContext' used in [Exposed] at $idlFile";
+                    die "Unsupported global context '$globalContext' used in [Exposed] at $idlFileName";
                 }
             }
             $windowConstructorsCode .= $windowAliases if $windowAliases;
@@ -211,13 +253,13 @@
 GeneratePartialInterface($testGlobalContextName, $testGlobalScopeConstructorsCode, $testGlobalScopeConstructorsFile) if defined($testGlobalContextName);
 
 # Resolves partial interfaces and include dependencies.
-foreach my $idlFile (sort keys %supplementalDependencies) {
-    my $baseFiles = $supplementalDependencies{$idlFile};
+foreach my $idlFilePath (sort keys %supplementalDependencies) {
+    my $baseFiles = $supplementalDependencies{$idlFilePath};
     foreach my $baseFile (@{$baseFiles}) {
-        my $targetIdlFile = $interfaceNameToIdlFile{$baseFile} or die "${baseFile}.idl not found, but it is supplemented by $idlFile";
-        push(@{$supplementals{$targetIdlFile}}, $idlFile);
+        my $targetIdlFilePath = $interfaceNameToIdlFilePath{$baseFile} or die "${baseFile}.idl not found, but it is supplemented by $idlFilePath";
+        push(@{$supplementals{$targetIdlFilePath}}, $idlFilePath);
     }
-    delete $supplementals{$idlFile};
+    delete $supplementals{$idlFilePath};
 }
 
 if ($isoSubspacesHeaderFile) {
@@ -238,17 +280,17 @@
 # Document.idl is supplemented by S.idl, and Event.idl is supplemented by no IDLs.
 # The IDL that supplements another IDL (e.g. P.idl) never appears in the dependency file.
 my $dependencies = "";
-foreach my $idlFile (sort keys %supplementals) {
-    $dependencies .= "$idlFile @{$supplementals{$idlFile}}\n";
+foreach my $idlFilePath (sort keys %supplementals) {
+    $dependencies .= "$idlFilePath @{$supplementals{$idlFilePath}}\n";
 }
 WriteFileIfChanged($supplementalDependencyFile, $dependencies);
 
 if ($supplementalMakefileDeps) {
     my $makefileDeps = "# Supplemental dependencies\n";
-    foreach my $idlFile (sort keys %supplementals) {
-        my $basename = $idlFileToInterfaceName{$idlFile};
+    foreach my $idlFilePath (sort keys %supplementals) {
+        my $basename = $idlFilePathToInterfaceName{$idlFilePath};
 
-        my @dependencyList = map { basename($_) } @{$supplementals{$idlFile}};
+        my @dependencyList = map { basename($_) } @{$supplementals{$idlFilePath}};
         my @dependencies = sort(keys %{{ map{$_=>1}@dependencyList}});
 
         $makefileDeps .= "JS${basename}.h: @{dependencies}\n";
@@ -301,7 +343,7 @@
     WriteFileIfChanged($destinationFile, $contents);
 
     my $fullPath = Cwd::realpath($destinationFile);
-    $supplementalDependencies{$fullPath} = [$interfaceName] if $interfaceNameToIdlFile{$interfaceName};
+    $supplementalDependencies{$fullPath} = [$interfaceName] if $interfaceNameToIdlFilePath{$interfaceName};
 }
 
 sub GenerateConstructorAttributes
@@ -351,27 +393,95 @@
     return ($code, $windowAliasesCode);
 }
 
-sub getFileContents
+sub trim
 {
-    my $idlFile = shift;
+    my $string = shift;
+    $string =~ s/^\s+|\s+$//g;
+    return $string;
+}
 
-    open my $file, "<", $idlFile or die "Could not open $idlFile for reading: $!";
+sub listsAreIdentical
+{
+    my ($list1, $list2) = @_;
+    
+    if (scalar(@{$list1}) != scalar(@{$list2})) {
+        return 0;
+    }
+    
+    for my $i (0 .. $#{$list1}) {
+        if ($list1->[$i] ne $list2->[$i]) {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+sub processIDL
+{
+    my $fileName = shift;
+    my $filePath = shift;
+
+    my $idlFile = IDLFile->new();
+    $idlFile->fileName($fileName);
+    
+    my $primaryDeclarationName = fileparse(basename($fileName), ".idl");
+    $idlFile->primaryDeclarationName($primaryDeclarationName);
+
+    open my $file, "<", $filePath or die "Could not open $idlFile for reading: $!";
     my @lines = <$file>;
     close $file;
 
+    # FIXME: It would be useful to remove all c/c++ style comments as well to reduce false parses. Perhaps we can use preprocessor.pm if it is not too expensive.
     # Filter out preprocessor lines.
     @lines = grep(!/^\s*#/, @lines);
 
-    return join('', @lines);
+    $idlFile->fileContents(join('', @lines));
+
+    if ($validateAgainstParser) {
+        my $parser = IDLParser->new(1);
+        $idlFile->parsedDocument($parser->Parse($filePath, $defines, $preprocessor, $idlAttributes));
+    }
+
+    return $idlFile;
 }
 
 sub getPartialNamesFromIDL
 {
-    my $fileContents = shift;
+    my $idlFile = shift;
+
+    my $fileContents = $idlFile->fileContents;
+
     my @partialNames = ();
-    while ($fileContents =~ /partial\s+(interface|dictionary)\s+(\w+)/mg) {
+    while ($fileContents =~ /partial\s+(interface|dictionary|namespace)\s+(\w+)/mg) {
         push(@partialNames, $2);
     }
+    
+    if ($validateAgainstParser) {
+        print("Validating getPartialNamesFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my @partialsFromParsedDocument = ();
+        foreach my $interface (@{$idlFile->parsedDocument->interfaces}) {
+            push(@partialsFromParsedDocument, $interface->type->name) if $interface->isPartial;
+        }
+        foreach my $dictionary (@{$idlFile->parsedDocument->dictionaries}) {
+            push(@partialsFromParsedDocument, $dictionary->type->name) if $dictionary->isPartial;
+        }
+        foreach my $namespace (@{$idlFile->parsedDocument->namespaces}) {
+            push(@partialsFromParsedDocument, $namespace->name) if $namespace->isPartial;
+        }
+
+        my @sortedPartialNames = sort @partialNames;
+        my @sortedPartialsFromParsedDocument = sort @partialsFromParsedDocument;
+
+        local $Data::Dumper::Terse = 1;
+        local $Data::Dumper::Indent = 0;
+        unless (listsAreIdentical(\@sortedPartialNames, \@sortedPartialsFromParsedDocument)) {
+            die "FAILURE: Partial declarations from regular _expression_ based parser (" . Dumper(@sortedPartialNames) . ") don't match those from validation parser (" . Dumper(@sortedPartialsFromParsedDocument) . ") [" . $idlFile->fileName . "].";
+        }
+        print "SUCCESS! Partial declarations from regular _expression_ based parser (" . Dumper(@sortedPartialNames) . ") match those from validation parser (" . Dumper(@sortedPartialsFromParsedDocument) . ").\n";
+    }
+    
     return \@partialNames;
 }
 
@@ -379,55 +489,175 @@
 # https://heycam.github.io/webidl/#includes-statement
 sub getIncludedInterfacesFromIDL
 {
-    my $fileContents = shift;
+    my $idlFile = shift;
     my $interfaceName = shift;
 
+    my $fileContents = $idlFile->fileContents;
+
     my @includedInterfaces = ();
     while ($fileContents =~ /^\s*(\w+)\s+includes\s+(\w+)\s*;/mg) {
         die "Identifier on the left of the 'includes' statement should be $interfaceName in $interfaceName.idl, but found $1" if $1 ne $interfaceName;
         push(@includedInterfaces, $2);
     }
+
+    if ($validateAgainstParser) {
+        print("Validating getIncludedInterfacesFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my @includedInterfacesFromParsedDocument = ();
+        foreach my $include (@{$idlFile->parsedDocument->includes}) {
+            push(@includedInterfacesFromParsedDocument, $include->mixinIdentifier);
+        }
+
+        my @sortedIncludedInterfaces = sort @includedInterfaces;
+        my @sortedIncludedInterfacesFromParsedDocument = sort @includedInterfacesFromParsedDocument;
+
+        local $Data::Dumper::Terse = 1;
+        local $Data::Dumper::Indent = 0;
+
+        unless (listsAreIdentical(\@sortedIncludedInterfaces, \@sortedIncludedInterfacesFromParsedDocument)) {
+            die "FAILURE: Included interfaces from regular _expression_ based parser (" . Dumper(@sortedIncludedInterfaces) . ") don't match those from validation parser (" . Dumper(@sortedIncludedInterfacesFromParsedDocument) . ") [" . $idlFile->fileName . "]";
+        }
+        print "SUCCESS! Included interfaces from regular _expression_ based parser (" . Dumper(@sortedIncludedInterfaces) . ") match those from validation parser (" . Dumper(@sortedIncludedInterfacesFromParsedDocument) . ").\n";
+    }
+
     return \@includedInterfaces
 }
 
 sub isCallbackInterfaceFromIDL
 {
-    my $fileContents = shift;
-    return ($fileContents =~ /callback\s+interface\s+\w+/gs);
+    my $idlFile = shift;
+
+    my $fileContents = $idlFile->fileContents;
+    my $containsCallbackInterface = ($fileContents =~ /callback\s+interface\s+\w+/gs);
+
+    if ($validateAgainstParser) {
+        print("Validating isCallbackInterfaceFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my $containsCallbackInterfaceFromParsedDocument = 0;
+        foreach my $interface (@{$idlFile->parsedDocument->interfaces}) {
+            if ($interface->isCallback) {
+                $containsCallbackInterfaceFromParsedDocument = 1;
+                last;
+            }
+        }
+
+        unless ($containsCallbackInterface == $containsCallbackInterfaceFromParsedDocument ) {
+            die "FAILURE: Determination of whether there is a callback interface from regular _expression_ based parser (" . ($containsCallbackInterface ? "YES" : "NO") . ") doesn't match the determination from the validation parser (" . ($containsCallbackInterfaceFromParsedDocument ? "YES" : "NO") . ") [" . $idlFile->fileName . "].";
+        }
+        print "SUCCESS! Determination of whether there is a callback interface from regular _expression_ based parser (" . ($containsCallbackInterface ? "YES" : "NO") . ") does match the determination from the validation parser (" . ($containsCallbackInterfaceFromParsedDocument ? "YES" : "NO") . ").\n";
+    }
+
+    return $containsCallbackInterface
 }
 
 sub isMixinInterfaceFromIDL
 {
-    my $fileContents = shift;
-    return ($fileContents =~ /interface\s+mixin\s+\w+/gs);
+    my $idlFile = shift;
+
+    my $fileContents = $idlFile->fileContents;
+    my $containsMixinInterface = ($fileContents =~ /interface\s+mixin\s+\w+/gs);
+
+    if ($validateAgainstParser) {
+        print("Validating isCallbackInterfaceFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my $containsMixinInterfaceFromParsedDocument = 0;
+        foreach my $interface (@{$idlFile->parsedDocument->interfaces}) {
+            if ($interface->isMixin) {
+                $containsMixinInterfaceFromParsedDocument = 1;
+                last;
+            }
+        }
+
+        unless ($containsMixinInterface == $containsMixinInterfaceFromParsedDocument ) {
+            die "FAILURE: Determination of whether there is a mixin interface from regular _expression_ based parser (" . ($containsMixinInterface ? "YES" : "NO") . ") doesn't match the determination from validation parser (" . ($containsMixinInterfaceFromParsedDocument ? "YES" : "NO") . ") [" . $idlFile->fileName . "].";
+        }
+        print "SUCCESS! Determination of whether there is a mixin interface from regular _expression_ based parser (" . ($containsMixinInterface ? "YES" : "NO") . ") does match the determination from validation parser (" . ($containsMixinInterfaceFromParsedDocument ? "YES" : "NO") . ").\n";
+    }
+
+    return $containsMixinInterface;
 }
 
-sub interfaceIsIterable
+sub containsIterableInterfaceFromIDL
 {
-    my $fileContents = shift;
-    return ($fileContents =~ /iterable\s*<\s*\w+\s*/gs);
+    my $idlFile = shift;
+
+    my $fileContents = $idlFile->fileContents;
+    my $containsIterableInterface = ($fileContents =~ /iterable\s*<\s*\w+\s*/gs);
+
+    if ($validateAgainstParser) {
+        print("Validating containsIterableInterfaceFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my $containsIterableInterfaceFromParsedDocument = 0;
+        foreach my $interface (@{$idlFile->parsedDocument->interfaces}) {
+            if ($interface->iterable) {
+                $containsIterableInterfaceFromParsedDocument = 1;
+                last;
+            }
+        }
+
+        unless ($containsIterableInterface == $containsIterableInterfaceFromParsedDocument ) {
+            die "FAILURE: Determination of whether there is an iterable interface from regular _expression_ based parser (" . ($containsIterableInterface ? "YES" : "NO") . ") doesn't match the determination from validation parser (" . ($containsIterableInterfaceFromParsedDocument ? "YES" : "NO") . ") [" . $idlFile->fileName . "].";
+        }
+        print "SUCCESS! Determination of whether there is an iterable interface from regular _expression_ based parser (" . ($containsIterableInterface ? "YES" : "NO") . ") does match the determination from validation parser (" . ($containsIterableInterfaceFromParsedDocument ? "YES" : "NO") . ").\n";
+    }
+
+    return $containsIterableInterface;
 }
 
-sub containsInterfaceFromIDL
+sub containsInterfaceOrCallbackInterfaceFromIDL
 {
-    my $fileContents = shift;
+    my $idlFile = shift;
 
-    return 1 if $fileContents =~ /\bcallback\s+interface\s+\w+/gs;
-    return 1 if $fileContents =~ /\binterface\s+\w+/gs;
-    return 0;
+    my $fileContents = $idlFile->fileContents;
+    my $containsInterfaceOrCallbackInterface = ($fileContents =~ /\b(callback interface|interface)\s+(\w+)/gs);
+
+    if ($validateAgainstParser) {
+        print("Validating containsInterfaceOrCallbackInterfaceFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my $containsInterfaceOrCallbackInterfaceFromParsedDocument = (@{$idlFile->parsedDocument->interfaces} > 0);
+
+        unless ($containsInterfaceOrCallbackInterface == $containsInterfaceOrCallbackInterfaceFromParsedDocument ) {
+            die "FAILURE: Determination of whether there is an interface or callback interface from regular _expression_ based parser (" . ($containsInterfaceOrCallbackInterface ? "YES" : "NO") . ") doesn't match the determination from validation parser (" . ($containsInterfaceOrCallbackInterfaceFromParsedDocument ? "YES" : "NO") . ") [" . $idlFile->fileName . "].";
+        }
+        print "SUCCESS! Determination of whether there is an interface or callback interface from regular _expression_ based parser (" . ($containsInterfaceOrCallbackInterface ? "YES" : "NO") . ") does match the determination from validation parser (" . ($containsInterfaceOrCallbackInterfaceFromParsedDocument ? "YES" : "NO") . ").\n";
+    }
+
+    return $containsInterfaceOrCallbackInterface;
 }
 
-sub trim
+sub containsInterfaceWithConstantsFromIDL
 {
-    my $string = shift;
-    $string =~ s/^\s+|\s+$//g;
-    return $string;
+    my $idlFile = shift;
+
+    my $fileContents = $idlFile->fileContents;
+    my $containsInterfaceWithConstants = ($fileContents =~ /\s+const[\s\w]+=\s+[\w]+;/gs);
+
+    if ($validateAgainstParser) {
+        print("Validating containsInterfaceWithConstantsFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my $containsInterfaceWithConstantsFromParsedDocument = 0;
+        foreach my $interface (@{$idlFile->parsedDocument->interfaces}) {
+            if (@{$interface->constants} > 0) {
+                $containsInterfaceWithConstantsFromParsedDocument = 1;
+                last;
+            }
+        }
+
+        unless ($containsInterfaceWithConstants == $containsInterfaceWithConstantsFromParsedDocument ) {
+            die "FAILURE: Determination of whether there is an interface with constants from regular _expression_ based parser (" . ($containsInterfaceWithConstants ? "YES" : "NO") . ") doesn't match the determination from validation parser (" . ($containsInterfaceWithConstantsFromParsedDocument ? "YES" : "NO") . ") [" . $idlFile->fileName . "].";
+        }
+        print "SUCCESS! Determination of whether there is an interface with constants from regular _expression_ based parser (" . ($containsInterfaceWithConstants ? "YES" : "NO") . ") does match the determination from validation parser (" . ($containsInterfaceWithConstantsFromParsedDocument ? "YES" : "NO") . ").\n";
+    }
+
+    return $containsInterfaceWithConstants;
 }
 
 sub getInterfaceExtendedAttributesFromIDL
 {
-    my $fileContents = shift;
+    my $idlFile = shift;
 
+    my $fileContents = $idlFile->fileContents;
+
     my $extendedAttributes = {};
 
     # Remove comments from fileContents before processing.
@@ -453,34 +683,92 @@
         }
     }
 
-    return $extendedAttributes;
-}
+    if ($validateAgainstParser) {
+        print("Validating getInterfaceExtendedAttributesFromIDL for " . $idlFile->fileName . " against validation parser.\n");
 
-sub interfaceHasConstantAttribute
-{
-    my $fileContents = shift;
+        my $primaryInterface;
+        foreach my $interface (@{$idlFile->parsedDocument->interfaces}) {
+            if ($interface->type->name eq $idlFile->primaryDeclarationName) {
+                $primaryInterface = $interface;
+                last;
+            }
+        }
 
-    return $fileContents =~ /\s+const[\s\w]+=\s+[\w]+;/gs;
-}
+        # FIXME: Comparing the deep structure of the extended attributes is suitably complex that for now
+        # we only validate that both parsers produce the same keys.
 
-sub shouldExposeInterface
-{
-    my $extendedAttributes = shift;
+        my @sortedExtendedAttributeKeys = sort keys %{$extendedAttributes};
+        my @sortedExtendedAttributeKeysFromParsedDocument = sort keys %{$primaryInterface->extendedAttributes};
 
-    return !$extendedAttributes->{"LegacyNoInterfaceObject"};
+        local $Data::Dumper::Terse = 1;
+        local $Data::Dumper::Indent = 0;
+
+        unless (listsAreIdentical(\@sortedExtendedAttributeKeys, \@sortedExtendedAttributeKeysFromParsedDocument)) {
+            die "FAILURE: Extended attributes for the primary interface from regular _expression_ based parser (" . Dumper(@sortedExtendedAttributeKeys) . ") don't match those from validation parser (" . Dumper(@sortedExtendedAttributeKeysFromParsedDocument) . ") [" . $idlFile->fileName . "]";
+        }
+        print "SUCCESS! Extended attributes for the primary interface from regular _expression_ based parser (" . Dumper(@sortedExtendedAttributeKeys) . ") match those from validation parser (" . Dumper(@sortedExtendedAttributeKeysFromParsedDocument) . ").\n";
+    }
+
+    return $extendedAttributes;
 }
 
-sub updateDictionaryDependencies
+sub getUndefinedBaseDictionariesFromIDL
 {
-    my $fileContents = shift;
     my $idlFile = shift;
 
-    my $dictionaryName = fileparse(basename($idlFile), ".idl");
+    my $fileContents = $idlFile->fileContents;
 
+    my @dictionaryNames = ();
+    while ($fileContents =~ /\s*dictionary\s+(\w+)\s*/mg) {
+        push(@dictionaryNames, $1)
+    }
+
+    $fileContents = $idlFile->fileContents;
     my @baseDictionaries = ();
     while ($fileContents =~ /\s*dictionary\s+(\w+)\s+:\s+(\w+)\s*/mg) {
-        next if !$interfaceNameToIdlFile{$2} || (grep { $_ eq $2 } @baseDictionaries);
+        next if (grep { $_ eq $2 } @dictionaryNames);
+        next if (grep { $_ eq $2 } @baseDictionaries);
         push(@baseDictionaries, $2);
     }
-    $dictionaryDependencies{$dictionaryName} = (join(".idl ", @baseDictionaries) . ".idl") if @baseDictionaries;
+
+    if ($validateAgainstParser) {
+        print("Validating getUndefinedBaseDictionariesFromIDL for " . $idlFile->fileName . " against validation parser.\n");
+
+        my @dictionaryNamesFromParsedDocument = ();
+        foreach my $dictionary (@{$idlFile->parsedDocument->dictionaries}) {
+            push(@dictionaryNamesFromParsedDocument, $dictionary->type->name);
+        }
+
+        my @baseDictionariesFromParsedDocument = ();
+        foreach my $dictionary (@{$idlFile->parsedDocument->dictionaries}) {
+            # Skip dictionaries without a base type.
+            next if !$dictionary->parentType;
+            # Skip dictionaries that have their base type defined in this document.
+            next if (grep { $_ eq $dictionary->parentType->name } @dictionaryNamesFromParsedDocument);
+            # Skip dictionaries that have already been added to the list.
+            next if (grep { $_ eq $dictionary->parentType->name } @baseDictionariesFromParsedDocument);
+
+            push(@baseDictionariesFromParsedDocument, $dictionary->parentType->name);
+        }
+
+        my @sortedBaseDictionaries = sort @baseDictionaries;
+        my @sortedBaseDictionariesFromParsedDocument = sort @baseDictionariesFromParsedDocument;
+
+        local $Data::Dumper::Terse = 1;
+        local $Data::Dumper::Indent = 0;
+
+        unless (listsAreIdentical(\@sortedBaseDictionaries, \@sortedBaseDictionariesFromParsedDocument)) {
+            die "FAILURE: Undefined base dictionaries from regular _expression_ based parser (" . Dumper(@sortedBaseDictionaries) . ") don't match those from validation parser (" . Dumper(@sortedBaseDictionariesFromParsedDocument) . ") [" . $idlFile->fileName . "]";
+        }
+        print "SUCCESS! Undefined base dictionaries from regular _expression_ based parser (" . Dumper(@sortedBaseDictionaries) . ") match those from validation parser (" . Dumper(@sortedBaseDictionariesFromParsedDocument) . ").\n";
+    }
+
+    return \@baseDictionaries;
 }
+
+sub shouldExposeInterface
+{
+    my $extendedAttributes = shift;
+
+    return !$extendedAttributes->{"LegacyNoInterfaceObject"};
+}

Modified: trunk/Source/WebCore/bindings/scripts/test/SupplementalDependencies.dep (266686 => 266687)


--- trunk/Source/WebCore/bindings/scripts/test/SupplementalDependencies.dep	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Source/WebCore/bindings/scripts/test/SupplementalDependencies.dep	2020-09-07 00:20:01 UTC (rev 266687)
@@ -267,3 +267,5 @@
 # Dictionaries dependencies
 JSTestDerivedDictionary.cpp: TestInheritedDictionary.idl
 JSTestDerivedDictionary2.cpp: TestInheritedDictionary.idl TestInheritedDictionary2.idl
+JSTestEventConstructor.cpp: EventInit.idl
+JSTestPromiseRejectionEvent.cpp: EventInit.idl

Modified: trunk/Tools/ChangeLog (266686 => 266687)


--- trunk/Tools/ChangeLog	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Tools/ChangeLog	2020-09-07 00:20:01 UTC (rev 266687)
@@ -1,3 +1,14 @@
+2020-09-06  Sam Weinig  <[email protected]>
+
+        [WebIDL] Add mode to preprocess-idls.pl to validate fast regex based scanner with the normal IDL parser
+        https://bugs.webkit.org/show_bug.cgi?id=216231
+
+        Reviewed by Darin Adler.
+
+        * Scripts/webkitpy/bindings/main.py:
+        (BindingsTests.generate_supplemental_dependency):
+        Update for rename from idlFilesList to idlFileNamesList and to pass the idlAttributesFile argument. 
+
 2020-09-06  Myles C. Maxfield  <[email protected]>
 
         Letter-spacing should disable ligatures

Modified: trunk/Tools/Scripts/webkitpy/bindings/main.py (266686 => 266687)


--- trunk/Tools/Scripts/webkitpy/bindings/main.py	2020-09-07 00:00:53 UTC (rev 266686)
+++ trunk/Tools/Scripts/webkitpy/bindings/main.py	2020-09-07 00:20:01 UTC (rev 266687)
@@ -86,9 +86,10 @@
         cmd = ['perl', '-w',
                '-IWebCore/bindings/scripts',
                'WebCore/bindings/scripts/preprocess-idls.pl',
-               '--idlFilesList', idl_files_list[1],
+               '--idlFileNamesList', idl_files_list[1],
                '--testGlobalContextName', 'TestGlobalObject',
                '--defines', '',
+               '--idlAttributesFile', 'WebCore/bindings/scripts/IDLAttributes.json',
                '--supplementalDependencyFile', supplemental_dependency_file,
                '--supplementalMakefileDeps', supplemental_makefile_dependency_file,
                '--windowConstructorsFile', window_constructors_file,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to