diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/bindings/scripts/CodeGenerator.pm | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/bindings/scripts/CodeGenerator.pm')
-rw-r--r-- | Source/WebCore/bindings/scripts/CodeGenerator.pm | 926 |
1 files changed, 660 insertions, 266 deletions
diff --git a/Source/WebCore/bindings/scripts/CodeGenerator.pm b/Source/WebCore/bindings/scripts/CodeGenerator.pm index 943959f54..6f77d7de5 100644 --- a/Source/WebCore/bindings/scripts/CodeGenerator.pm +++ b/Source/WebCore/bindings/scripts/CodeGenerator.pm @@ -28,14 +28,16 @@ package CodeGenerator; use strict; +use File::Basename; use File::Find; +use Carp qw<longmess>; +use Data::Dumper; my $useDocument = ""; my $useGenerator = ""; my $useOutputDir = ""; my $useOutputHeadersDir = ""; my $useDirectories = ""; -my $useLayerOnTop = 0; my $preprocessor; my $writeDependencies = 0; my $defines = ""; @@ -45,59 +47,88 @@ my $codeGenerator = 0; my $verbose = 0; -my %numericTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1, - "unsigned int" => 1, "unsigned short" => 1, - "unsigned long" => 1, "unsigned long long" => 1, - "float" => 1, "double" => 1, "byte" => 1, - "octet" => 1); +my %integerTypeHash = ( + "byte" => 1, + "long long" => 1, + "long" => 1, + "octet" => 1, + "short" => 1, + "unsigned long long" => 1, + "unsigned long" => 1, + "unsigned short" => 1, +); -my %primitiveTypeHash = ( "boolean" => 1, "void" => 1, "Date" => 1); +my %floatingPointTypeHash = ( + "float" => 1, + "unrestricted float" => 1, + "double" => 1, + "unrestricted double" => 1, +); -my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1); +my %stringTypeHash = ( + "ByteString" => 1, + "DOMString" => 1, + "USVString" => 1, +); -# WebCore types used directly in IDL files. -my %webCoreTypeHash = ( - "CompareHow" => 1, - "SerializedScriptValue" => 1, - "Dictionary" => 1 +my %typedArrayTypes = ( + "ArrayBuffer" => 1, + "ArrayBufferView" => 1, + "DataView" => 1, + "Float32Array" => 1, + "Float64Array" => 1, + "Int16Array" => 1, + "Int32Array" => 1, + "Int8Array" => 1, + "Uint16Array" => 1, + "Uint32Array" => 1, + "Uint8Array" => 1, + "Uint8ClampedArray" => 1, ); -my %enumTypeHash = (); - -my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1); - -my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1, - "onerror" => 1, "onload" => 1, "onmousedown" => 1, - "onmouseenter" => 1, "onmouseleave" => 1, - "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1, - "onmouseup" => 1, "onresize" => 1, "onscroll" => 1, - "onunload" => 1); - -my %svgTypeNeedingTearOff = ( - "SVGAngle" => "SVGPropertyTearOff<SVGAngle>", - "SVGLength" => "SVGPropertyTearOff<SVGLength>", - "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>", - "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>", - "SVGNumber" => "SVGPropertyTearOff<float>", - "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>", - "SVGPathSegList" => "SVGPathSegListPropertyTearOff", - "SVGPoint" => "SVGPropertyTearOff<SVGPoint>", - "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>", - "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>", - "SVGRect" => "SVGPropertyTearOff<FloatRect>", - "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>", - "SVGTransform" => "SVGPropertyTearOff<SVGTransform>", - "SVGTransformList" => "SVGTransformListPropertyTearOff" +my %primitiveTypeHash = ( + "boolean" => 1, + "void" => 1, + "Date" => 1 ); -my %svgTypeWithWritablePropertiesNeedingTearOff = ( - "SVGPoint" => 1, - "SVGMatrix" => 1 +my %dictionaryTypeImplementationNameOverrides = (); +my %enumTypeImplementationNameOverrides = (); + +my %svgAttributesInHTMLHash = ( + "class" => 1, + "id" => 1, + "onabort" => 1, + "onclick" => 1, + "onerror" => 1, + "onload" => 1, + "onmousedown" => 1, + "onmouseenter" => 1, + "onmouseleave" => 1, + "onmousemove" => 1, + "onmouseout" => 1, + "onmouseover" => 1, + "onmouseup" => 1, + "onresize" => 1, + "onscroll" => 1, + "onunload" => 1, ); # Cache of IDL file pathnames. my $idlFiles; my $cachedInterfaces = {}; +my $cachedExternalDictionaries = {}; +my $cachedExternalEnumerations = {}; + +sub assert +{ + my $message = shift; + + my $mess = longmess(); + print Dumper($mess); + + die $message; +} # Default constructor sub new @@ -109,7 +140,6 @@ sub new $useGenerator = shift; $useOutputDir = shift; $useOutputHeadersDir = shift; - $useLayerOnTop = shift; $preprocessor = shift; $writeDependencies = shift; $verbose = shift; @@ -128,24 +158,86 @@ sub ProcessDocument my $ifaceName = "CodeGenerator" . $useGenerator; require $ifaceName . ".pm"; - %enumTypeHash = map { $_->name => $_->values } @{$useDocument->enumerations}; + foreach my $dictionary (@{$useDocument->dictionaries}) { + if ($dictionary->extendedAttributes->{"ImplementedAs"}) { + $dictionaryTypeImplementationNameOverrides{$dictionary->type->name} = $dictionary->extendedAttributes->{"ImplementedAs"}; + } + } + + foreach my $enumeration (@{$useDocument->enumerations}) { + if ($enumeration->extendedAttributes->{"ImplementedAs"}) { + $enumTypeImplementationNameOverrides{$enumeration->type->name} = $enumeration->extendedAttributes->{"ImplementedAs"}; + } + } # Dynamically load external code generation perl module - $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose, $targetIdlFilePath); + $codeGenerator = $ifaceName->new($object, $writeDependencies, $verbose, $targetIdlFilePath); unless (defined($codeGenerator)) { my $interfaces = $useDocument->interfaces; foreach my $interface (@$interfaces) { - print "Skipping $useGenerator code generation for IDL interface \"" . $interface->name . "\".\n" if $verbose; + print "Skipping $useGenerator code generation for IDL interface \"" . $interface->type->name . "\".\n" if $verbose; } return; } my $interfaces = $useDocument->interfaces; - foreach my $interface (@$interfaces) { - print "Generating $useGenerator bindings code for IDL interface \"" . $interface->name . "\"...\n" if $verbose; - $codeGenerator->GenerateInterface($interface, $defines); + if (@$interfaces) { + die "Multiple interfaces per document are not supported" if @$interfaces > 1; + + my $interface = @$interfaces[0]; + print "Generating $useGenerator bindings code for IDL interface \"" . $interface->type->name . "\"...\n" if $verbose; + $codeGenerator->GenerateInterface($interface, $defines, $useDocument->enumerations, $useDocument->dictionaries); $codeGenerator->WriteData($interface, $useOutputDir, $useOutputHeadersDir); + return; + } + + my $callbackFunctions = $useDocument->callbackFunctions; + if (@$callbackFunctions) { + die "Multiple standalone callback functions per document are not supported" if @$callbackFunctions > 1; + + my $callbackFunction = @$callbackFunctions[0]; + print "Generating $useGenerator bindings code for IDL callback function \"" . $callbackFunction->type->name . "\"...\n" if $verbose; + $codeGenerator->GenerateCallbackFunction($callbackFunction, $useDocument->enumerations, $useDocument->dictionaries); + $codeGenerator->WriteData($callbackFunction, $useOutputDir, $useOutputHeadersDir); + return; + } + + my $dictionaries = $useDocument->dictionaries; + if (@$dictionaries) { + my $dictionary; + my $otherDictionaries; + if (@$dictionaries == 1) { + $dictionary = @$dictionaries[0]; + } else { + my $primaryDictionaryName = fileparse($targetIdlFilePath, ".idl"); + for my $candidate (@$dictionaries) { + if ($candidate->type->name eq $primaryDictionaryName) { + $dictionary = $candidate; + } else { + push @$otherDictionaries, $candidate; + } + } + die "Multiple dictionaries per document are only supported if one matches the filename" unless $dictionary; + } + + print "Generating $useGenerator bindings code for IDL dictionary \"" . $dictionary->type->name . "\"...\n" if $verbose; + $codeGenerator->GenerateDictionary($dictionary, $useDocument->enumerations, $otherDictionaries); + $codeGenerator->WriteData($dictionary, $useOutputDir, $useOutputHeadersDir); + return; } + + my $enumerations = $useDocument->enumerations; + if (@$enumerations) { + die "Multiple standalone enumerations per document are not supported" if @$enumerations > 1; + + my $enumeration = @$enumerations[0]; + print "Generating $useGenerator bindings code for IDL enumeration \"" . $enumeration->type->name . "\"...\n" if $verbose; + $codeGenerator->GenerateEnumeration($enumeration); + $codeGenerator->WriteData($enumeration, $useOutputDir, $useOutputHeadersDir); + return; + } + + die "Processing document " . $useDocument->fileName . " did not generate anything" } sub FileNamePrefix @@ -156,7 +248,7 @@ sub FileNamePrefix require $ifaceName . ".pm"; # Dynamically load external code generation perl module - $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose); + $codeGenerator = $ifaceName->new($object, $writeDependencies, $verbose); return $codeGenerator->FileNamePrefix(); } @@ -166,7 +258,9 @@ sub UpdateFile my $fileName = shift; my $contents = shift; - open FH, "> $fileName" or die "Couldn't open $fileName: $!\n"; + # FIXME: We should only write content if it is different from what is in the file. + # But that would mean running more often the binding generator, see https://bugs.webkit.org/show_bug.cgi?id=131756 + open FH, ">", $fileName or die "Couldn't open $fileName: $!\n"; print FH $contents; close FH; } @@ -183,8 +277,8 @@ sub ForAllParents my $outerInterface = shift; my $currentInterface = shift; - for (@{$currentInterface->parents}) { - my $interfaceName = $_; + if ($currentInterface->parentType) { + my $interfaceName = $currentInterface->parentType->name; my $parentInterface = $object->ParseInterface($outerInterface, $interfaceName); if ($beforeRecursion) { @@ -198,22 +292,6 @@ sub ForAllParents &$recurse($interface, $interface); } -sub FindSuperMethod -{ - my ($object, $interface, $functionName) = @_; - my $indexer; - $object->ForAllParents($interface, undef, sub { - my $currentInterface = shift; - foreach my $function (@{$currentInterface->functions}) { - if ($function->signature->name eq $functionName) { - $indexer = $function->signature; - return 'prune'; - } - } - }); - return $indexer; -} - sub IDLFileForInterface { my $object = shift; @@ -236,6 +314,26 @@ sub IDLFileForInterface return $idlFiles->{$interfaceName}; } +sub GetInterfaceForAttribute +{ + my ($object, $currentInterface, $attribute) = @_; + + return undef unless $object->IsInterfaceType($attribute->type); + + return $object->ParseInterface($currentInterface, $attribute->type->name); +} + +sub GetAttributeFromInterface +{ + my ($object, $outerInterface, $interfaceName, $attributeName) = @_; + + my $interface = $object->ParseInterface($outerInterface, $interfaceName); + for my $attribute (@{$interface->attributes}) { + return $attribute if $attribute->name eq $attributeName; + } + die("Could not find attribute '$attributeName' on interface '$interfaceName'."); +} + sub ParseInterface { my $object = shift; @@ -243,6 +341,7 @@ sub ParseInterface my $interfaceName = shift; return undef if $interfaceName eq 'Object'; + return undef if $interfaceName eq 'UNION'; if (exists $cachedInterfaces->{$interfaceName}) { return $cachedInterfaces->{$interfaceName}; @@ -250,7 +349,7 @@ sub ParseInterface # Step #1: Find the IDL file associated with 'interface' my $filename = $object->IDLFileForInterface($interfaceName) - or die("Could NOT find IDL file for interface \"$interfaceName\", reachable from \"" . $outerInterface->name . "\"!\n"); + or assert("Could NOT find IDL file for interface \"$interfaceName\", reachable from \"" . $outerInterface->type->name . "\"!\n"); print " | |> Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose; @@ -259,7 +358,7 @@ sub ParseInterface my $document = $parser->Parse($filename, $defines, $preprocessor); foreach my $interface (@{$document->interfaces}) { - if ($interface->name eq $interfaceName) { + if ($interface->type->name eq $interfaceName) { $cachedInterfaces->{$interfaceName} = $interface; return $interface; } @@ -270,197 +369,330 @@ sub ParseInterface # Helpers for all CodeGenerator***.pm modules -sub SkipIncludeHeader +sub IsNumericType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 1 if $object->IsPrimitiveType($type); + assert("Not a type") if ref($type) ne "IDLType"; - # Special case: SVGNumber.h does not exist. - return 1 if $type eq "SVGNumber"; - - # Typed arrays already included by JSDOMBinding.h. - return 1 if $object->IsTypedArrayType($type); + return 1 if $integerTypeHash{$type->name}; + return 1 if $floatingPointTypeHash{$type->name}; + return 0; +} + +sub IsStringOrEnumType +{ + my ($object, $type) = @_; + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $object->IsStringType($type); + return 1 if $object->IsEnumType($type); return 0; } -sub IsConstructorTemplate +sub IsIntegerType { - my $object = shift; - my $interface = shift; - my $template = shift; + my ($object, $type) = @_; - return $interface->extendedAttributes->{"ConstructorTemplate"} && $interface->extendedAttributes->{"ConstructorTemplate"} eq $template; + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $integerTypeHash{$type->name}; + return 0; } -sub IsNumericType +sub IsFloatingPointType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 1 if $numericTypeHash{$type}; + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $floatingPointTypeHash{$type->name}; return 0; } sub IsPrimitiveType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 1 if $primitiveTypeHash{$type}; - return 1 if $numericTypeHash{$type}; + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $primitiveTypeHash{$type->name}; + return 1 if $object->IsNumericType($type); return 0; } sub IsStringType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 1 if $stringTypeHash{$type}; + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $stringTypeHash{$type->name}; return 0; } sub IsEnumType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 1 if exists $enumTypeHash{$type}; - return 0; + assert("Not a type") if ref($type) ne "IDLType"; + + return defined($object->GetEnumByType($type)); } -sub ValidEnumValues +sub GetEnumByType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + my $name = $type->name; + + die "GetEnumByType() was called with an undefined enumeration name" unless defined($name); + + for my $enumeration (@{$useDocument->enumerations}) { + return $enumeration if $enumeration->type->name eq $name; + } + + return $cachedExternalEnumerations->{$name} if exists($cachedExternalEnumerations->{$name}); - return @{$enumTypeHash{$type}}; + # Find the IDL file associated with the dictionary. + my $filename = $object->IDLFileForInterface($name) or return; + + # Do a fast check to see if it seems to contain a dictionary. + my $fileContents = slurp($filename); + + if ($fileContents =~ /\benum\s+$name/gs) { + # Parse the IDL. + my $parser = IDLParser->new(1); + my $document = $parser->Parse($filename, $defines, $preprocessor); + + foreach my $enumeration (@{$document->enumerations}) { + next unless $enumeration->type->name eq $name; + + $cachedExternalEnumerations->{$name} = $enumeration; + my $implementedAs = $enumeration->extendedAttributes->{ImplementedAs}; + $enumTypeImplementationNameOverrides{$enumeration->type->name} = $implementedAs if $implementedAs; + return $enumeration; + } + } + $cachedExternalEnumerations->{$name} = undef; } -sub IsNonPointerType +# An enumeration defined in its own IDL file. +sub IsExternalEnumType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type} or $numericTypeHash{$type}; + assert("Not a type") if ref($type) ne "IDLType"; + + return $object->IsEnumType($type) && defined($cachedExternalEnumerations->{$type->name}); +} + +sub HasEnumImplementationNameOverride +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if exists $enumTypeImplementationNameOverrides{$type->name}; return 0; } -sub IsSVGTypeNeedingTearOff +sub GetEnumImplementationNameOverride { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return $enumTypeImplementationNameOverrides{$type->name}; +} + +sub GetDictionaryByType +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + my $name = $type->name; + + die "GetDictionaryByType() was called with an undefined dictionary name" unless defined($name); + + for my $dictionary (@{$useDocument->dictionaries}) { + return $dictionary if $dictionary->type->name eq $name; + } - return 1 if exists $svgTypeNeedingTearOff{$type}; + return $cachedExternalDictionaries->{$name} if exists($cachedExternalDictionaries->{$name}); + + # Find the IDL file associated with the dictionary. + my $filename = $object->IDLFileForInterface($name) or return; + + # Do a fast check to see if it seems to contain a dictionary. + my $fileContents = slurp($filename); + + if ($fileContents =~ /\bdictionary\s+$name/gs) { + # Parse the IDL. + my $parser = IDLParser->new(1); + my $document = $parser->Parse($filename, $defines, $preprocessor); + + foreach my $dictionary (@{$document->dictionaries}) { + next unless $dictionary->type->name eq $name; + + $cachedExternalDictionaries->{$name} = $dictionary; + my $implementedAs = $dictionary->extendedAttributes->{ImplementedAs}; + $dictionaryTypeImplementationNameOverrides{$dictionary->type->name} = $implementedAs if $implementedAs; + return $dictionary; + } + } + $cachedExternalDictionaries->{$name} = undef; +} + +sub IsDictionaryType +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return $type->name =~ /^[A-Z]/ && defined($object->GetDictionaryByType($type)); +} + +# A dictionary defined in its own IDL file. +sub IsExternalDictionaryType +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return $object->IsDictionaryType($type) && defined($cachedExternalDictionaries->{$type->name}); +} + +sub HasDictionaryImplementationNameOverride +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if exists $dictionaryTypeImplementationNameOverrides{$type->name}; return 0; } -sub IsSVGTypeWithWritablePropertiesNeedingTearOff +sub GetDictionaryImplementationNameOverride { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return $dictionaryTypeImplementationNameOverrides{$type->name}; +} - return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type}; +sub IsNonPointerType +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $object->IsPrimitiveType($type); return 0; } sub IsTypedArrayType { - my $object = shift; - my $type = shift; - return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView")); - return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array")); - return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array")); - return 1 if (($type eq "Float32Array") or ($type eq "Float64Array") or ($type eq "DataView")); + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $typedArrayTypes{$type->name}; return 0; } sub IsRefPtrType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; return 0 if $object->IsPrimitiveType($type); - return 0 if $object->GetArrayType($type); - return 0 if $object->GetSequenceType($type); - return 0 if $type eq "DOMString"; + return 0 if $object->IsDictionaryType($type); return 0 if $object->IsEnumType($type); + return 0 if $object->IsSequenceOrFrozenArrayType($type); + return 0 if $object->IsRecordType($type); + return 0 if $object->IsStringType($type); + return 0 if $type->isUnion; + return 0 if $type->name eq "any"; + return 0 if $type->name eq "object"; return 1; } -sub GetSVGTypeNeedingTearOff +sub IsSVGAnimatedTypeName { - my $object = shift; - my $type = shift; + my ($object, $typeName) = @_; - return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type}; - return undef; + return $typeName =~ /^SVGAnimated/; } -sub GetSVGWrappedTypeNeedingTearOff +sub IsSVGAnimatedType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; - my $svgTypeNeedingTearOff = $object->GetSVGTypeNeedingTearOff($type); - return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff; + return $object->IsSVGAnimatedTypeName($type->name); +} - if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) { - $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//; - } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) { - $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//; - } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) { - $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//; - } elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) { - $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//; - } +sub IsConstructorType +{ + my ($object, $type) = @_; - $svgTypeNeedingTearOff =~ s/>//; - return $svgTypeNeedingTearOff; + assert("Not a type") if ref($type) ne "IDLType"; + + return $type->name =~ /Constructor$/; } -sub IsSVGAnimatedType +sub IsSequenceType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; - return $type =~ /^SVGAnimated/; + return $type->name eq "sequence"; } -sub GetSequenceType +sub IsFrozenArrayType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; - return $1 if $type =~ /^sequence<([\w\d_\s]+)>.*/; - return ""; + return $type->name eq "FrozenArray"; } -sub GetArrayType +sub IsSequenceOrFrozenArrayType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; - return $1 if $type =~ /^([\w\d_\s]+)\[\]/; - return ""; + return $object->IsSequenceType($type) || $object->IsFrozenArrayType($type); } -sub AssertNotSequenceType +sub IsRecordType { - my $object = shift; - my $type = shift; - die "Sequences must not be used as the type of an attribute, constant or exception field." if $object->GetSequenceType($type); + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return $type->name eq "record"; } +# These match WK_lcfirst and WK_ucfirst defined in builtins_generator.py. # Uppercase the first letter while respecting WebKit style guidelines. # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. sub WK_ucfirst { my ($object, $param) = @_; + my $ret = ucfirst($param); $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; $ret =~ s/Svg/SVG/ if $ret =~ /^Svg/; @@ -473,13 +705,16 @@ sub WK_ucfirst sub WK_lcfirst { my ($object, $param) = @_; + my $ret = lcfirst($param); + $ret =~ s/dOM/dom/ if $ret =~ /^dOM/; $ret =~ s/hTML/html/ if $ret =~ /^hTML/; $ret =~ s/uRL/url/ if $ret =~ /^uRL/; $ret =~ s/jS/js/ if $ret =~ /^jS/; $ret =~ s/xML/xml/ if $ret =~ /^xML/; $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/; $ret =~ s/cSS/css/ if $ret =~ /^cSS/; + $ret =~ s/rTC/rtc/ if $ret =~ /^rTC/; # For HTML5 FileSystem API Flags attributes. # (create is widely used to instantiate an object and must be avoided.) @@ -489,10 +724,30 @@ sub WK_lcfirst return $ret; } +sub slurp +{ + my $file = shift; + + open my $fh, '<', $file or die; + local $/ = undef; + my $content = <$fh>; + close $fh; + return $content; +} + +sub trim +{ + my $string = shift; + + $string =~ s/^\s+|\s+$//g; + return $string; +} + # Return the C++ namespace that a given attribute name string is defined in. sub NamespaceForAttributeName { my ($object, $interfaceName, $attributeName) = @_; + return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName}; return "HTMLNames"; } @@ -505,23 +760,30 @@ sub LinkOverloadedFunctions my %nameToFunctionsMap = (); foreach my $function (@{$interface->functions}) { - my $name = $function->signature->name; + my $name = $function->name; $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name}; push(@{$nameToFunctionsMap{$name}}, $function); $function->{overloads} = $nameToFunctionsMap{$name}; $function->{overloadIndex} = @{$nameToFunctionsMap{$name}}; } + + my $index = 1; + foreach my $constructor (@{$interface->constructors}) { + $constructor->{overloads} = $interface->constructors; + $constructor->{overloadIndex} = $index; + $index++; + } } sub AttributeNameForGetterAndSetter { my ($generator, $attribute) = @_; - my $attributeName = $attribute->signature->name; - if ($attribute->signature->extendedAttributes->{"ImplementedAs"}) { - $attributeName = $attribute->signature->extendedAttributes->{"ImplementedAs"}; + my $attributeName = $attribute->name; + if ($attribute->extendedAttributes->{"ImplementedAs"}) { + $attributeName = $attribute->extendedAttributes->{"ImplementedAs"}; } - my $attributeType = $attribute->signature->type; + my $attributeType = $attribute->type; # SVG animated types need to use a special attribute name. # The rest of the special casing for SVG animated types is handled in the language-specific code generators. @@ -534,7 +796,7 @@ sub ContentAttributeName { my ($generator, $implIncludes, $interfaceName, $attribute) = @_; - my $contentAttributeName = $attribute->signature->extendedAttributes->{"Reflect"}; + my $contentAttributeName = $attribute->extendedAttributes->{"Reflect"}; return undef if !$contentAttributeName; $contentAttributeName = lc $generator->AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "VALUE_IS_MISSING"; @@ -555,16 +817,16 @@ sub GetterExpression return ($generator->WK_lcfirst($generator->AttributeNameForGetterAndSetter($attribute))); } - my $attributeType = $attribute->signature->type; + my $attributeType = $attribute->type; my $functionName; - if ($attribute->signature->extendedAttributes->{"URL"}) { + if ($attribute->extendedAttributes->{"URL"}) { $functionName = "getURLAttribute"; - } elsif ($attributeType eq "boolean") { - $functionName = "fastHasAttribute"; - } elsif ($attributeType eq "long") { + } elsif ($attributeType->name eq "boolean") { + $functionName = "hasAttributeWithoutSynchronization"; + } elsif ($attributeType->name eq "long") { $functionName = "getIntegralAttribute"; - } elsif ($attributeType eq "unsigned long") { + } elsif ($attributeType->name eq "unsigned long") { $functionName = "getUnsignedIntegralAttribute"; } else { if ($contentAttributeName eq "WebCore::HTMLNames::idAttr") { @@ -576,7 +838,7 @@ sub GetterExpression } elsif ($generator->IsSVGAnimatedType($attributeType)) { $functionName = "getAttribute"; } else { - $functionName = "fastGetAttribute"; + $functionName = "attributeWithoutSynchronization"; } } @@ -593,74 +855,209 @@ sub SetterExpression return ("set" . $generator->WK_ucfirst($generator->AttributeNameForGetterAndSetter($attribute))); } + my $attributeType = $attribute->type; + my $functionName; - if ($attribute->signature->type eq "boolean") { + if ($attributeType->name eq "boolean") { $functionName = "setBooleanAttribute"; - } elsif ($attribute->signature->type eq "long") { + } elsif ($attributeType->name eq "long") { $functionName = "setIntegralAttribute"; - } elsif ($attribute->signature->type eq "unsigned long") { + } elsif ($attributeType->name eq "unsigned long") { $functionName = "setUnsignedIntegralAttribute"; - } else { + } elsif ($generator->IsSVGAnimatedType($attributeType)) { $functionName = "setAttribute"; + } else { + $functionName = "setAttributeWithoutSynchronization"; } return ($functionName, $contentAttributeName); } -sub IsWrapperType +sub IsBuiltinType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 0 if $object->IsPrimitiveType($type); - return 0 if $object->GetArrayType($type); - return 0 if $object->GetSequenceType($type); + assert("Not a type") if ref($type) ne "IDLType"; + + return 1 if $object->IsPrimitiveType($type); + return 1 if $object->IsSequenceOrFrozenArrayType($type); + return 1 if $object->IsRecordType($type); + return 1 if $object->IsStringType($type); + return 1 if $object->IsTypedArrayType($type); + return 1 if $type->isUnion; + return 1 if $type->name eq "BufferSource"; + return 1 if $type->name eq "EventListener"; + return 1 if $type->name eq "JSON"; + return 1 if $type->name eq "Promise"; + return 1 if $type->name eq "SerializedScriptValue"; + return 1 if $type->name eq "XPathNSResolver"; + return 1 if $type->name eq "any"; + return 1 if $type->name eq "object"; + + return 0; +} + +sub IsInterfaceType +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 0 if $object->IsBuiltinType($type); + return 0 if $object->IsDictionaryType($type); return 0 if $object->IsEnumType($type); - return 0 if $object->IsStringType($type); - return 0 if $object->IsTypedArrayType($type); - return 0 if $webCoreTypeHash{$type}; - return 0 if $type eq "any"; return 1; } -sub IsCallbackInterface +sub IsWrapperType { - my $object = shift; - my $type = shift; + my ($object, $type) = @_; - return 0 unless $object->IsWrapperType($type); + assert("Not a type") if ref($type) ne "IDLType"; - my $idlFile = $object->IDLFileForInterface($type) - or die("Could NOT find IDL file for interface \"$type\"!\n"); + return 1 if $object->IsInterfaceType($type); + return 1 if $type->name eq "XPathNSResolver"; - open FILE, "<", $idlFile; - my @lines = <FILE>; - close FILE; + return 0; +} + +sub IsSerializableAttribute +{ + my ($object, $currentInterface, $attribute) = @_; + + # https://heycam.github.io/webidl/#dfn-serializable-type + + my $type = $attribute->type; + return 1 if $type->name eq "boolean"; + return 1 if $object->IsNumericType($type); + return 1 if $object->IsEnumType($type); + return 1 if $object->IsStringType($type); + return 0 if $type->name eq "EventHandler"; + + if ($type->isUnion || $object->IsSequenceType($type) || $object->IsDictionaryType($type)) { + die "Serializer for non-primitive types is not currently supported\n"; + } - my $fileContents = join('', @lines); - return ($fileContents =~ /callback\s+interface\s+(\w+)/gs); + my $interface = GetInterfaceForAttribute($object, $currentInterface, $attribute); + if ($interface && $interface->serializable) { + die "Serializer for non-primitive types is not currently supported\n"; + } + + return 0; } -sub GenerateConditionalString +sub GetInterfaceExtendedAttributesFromName { - my $generator = shift; - my $node = shift; + # FIXME: It's bad to have a function like this that opens another IDL file to answer a question. + # Overusing this kind of function can make things really slow. Lets avoid these if we can. - my $conditional = $node->extendedAttributes->{"Conditional"}; - if ($conditional) { - return $generator->GenerateConditionalStringFromAttributeValue($conditional); - } else { - return ""; + my ($object, $interfaceName) = @_; + + my $idlFile = $object->IDLFileForInterface($interfaceName) or assert("Could NOT find IDL file for interface \"$interfaceName\"!\n"); + + open FILE, "<", $idlFile or die; + my @lines = <FILE>; + close FILE; + + my $fileContents = join('', @lines); + + my $extendedAttributes = {}; + + if ($fileContents =~ /\[(.*)\]\s+(callback interface|interface|exception)\s+(\w+)/gs) { + my @parts = split(',', $1); + foreach my $part (@parts) { + my @keyValue = split('=', $part); + my $key = trim($keyValue[0]); + next unless length($key); + my $value = "VALUE_IS_MISSING"; + $value = trim($keyValue[1]) if @keyValue > 1; + $extendedAttributes->{$key} = $value; + } } + + return $extendedAttributes; +} + +sub ComputeIsCallbackInterface +{ + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 0 unless $object->IsInterfaceType($type); + + my $typeName = $type->name; + my $idlFile = $object->IDLFileForInterface($typeName) or assert("Could NOT find IDL file for interface \"$typeName\"!\n"); + + open FILE, "<", $idlFile or die; + my @lines = <FILE>; + close FILE; + + my $fileContents = join('', @lines); + return ($fileContents =~ /callback\s+interface\s+(\w+)/gs); +} + +my %isCallbackInterface = (); + +sub IsCallbackInterface +{ + # FIXME: It's bad to have a function like this that opens another IDL file to answer a question. + # Overusing this kind of function can make things really slow. Lets avoid these if we can. + # To mitigate that, lets cache what we learn in a hash so we don't open the same file over and over. + + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return $isCallbackInterface{$type->name} if exists $isCallbackInterface{$type->name}; + my $result = $object->ComputeIsCallbackInterface($type); + $isCallbackInterface{$type->name} = $result; + return $result; } -sub GenerateConstructorConditionalString +sub ComputeIsCallbackFunction { - my $generator = shift; - my $node = shift; + my ($object, $type) = @_; + + assert("Not a type") if ref($type) ne "IDLType"; + + return 0 unless $object->IsInterfaceType($type); + + my $typeName = $type->name; + my $idlFile = $object->IDLFileForInterface($typeName) or assert("Could NOT find IDL file for interface \"$typeName\"!\n"); + + open FILE, "<", $idlFile or die; + my @lines = <FILE>; + close FILE; + + my $fileContents = join('', @lines); + return ($fileContents =~ /(.*)callback\s+(\w+)\s+=/gs); +} + +my %isCallbackFunction = (); + +sub IsCallbackFunction +{ + # FIXME: It's bad to have a function like this that opens another IDL file to answer a question. + # Overusing this kind of function can make things really slow. Lets avoid these if we can. + # To mitigate that, lets cache what we learn in a hash so we don't open the same file over and over. + + my ($object, $type) = @_; - my $conditional = $node->extendedAttributes->{"ConstructorConditional"}; + assert("Not a type") if ref($type) ne "IDLType"; + + return $isCallbackFunction{$type->name} if exists $isCallbackFunction{$type->name}; + my $result = $object->ComputeIsCallbackFunction($type); + $isCallbackFunction{$type->name} = $result; + return $result; +} + +sub GenerateConditionalString +{ + my ($generator, $node) = @_; + + my $conditional = $node->extendedAttributes->{"Conditional"}; if ($conditional) { return $generator->GenerateConditionalStringFromAttributeValue($conditional); } else { @@ -670,51 +1067,49 @@ sub GenerateConstructorConditionalString sub GenerateConditionalStringFromAttributeValue { - my $generator = shift; - my $conditional = shift; - - my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : '')); - if ($operator) { - # Avoid duplicated conditions. - my %conditions; - map { $conditions{$_} = 1 } split('\\' . $operator, $conditional); - return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")"; - } else { - return "ENABLE(" . $conditional . ")"; - } + my ($generator, $conditional) = @_; + + my %disjunction; + map { + my $expression = $_; + my %conjunction; + map { $conjunction{$_} = 1; } split(/&/, $expression); + $expression = "ENABLE(" . join(") && ENABLE(", sort keys %conjunction) . ")"; + $disjunction{$expression} = 1 + } split(/\|/, $conditional); + + return "1" if keys %disjunction == 0; + return (%disjunction)[0] if keys %disjunction == 1; + + my @parenthesized; + map { + my $expression = $_; + $expression = "($expression)" if $expression =~ / /; + push @parenthesized, $expression; + } sort keys %disjunction; + + return join(" || ", @parenthesized); } sub GenerateCompileTimeCheckForEnumsIfNeeded { my ($generator, $interface) = @_; - my $interfaceName = $interface->name; - my @checks = (); - # If necessary, check that all constants are available as enums with the same value. - if (!$interface->extendedAttributes->{"DoNotCheckConstants"} && @{$interface->constants}) { - push(@checks, "\n"); - foreach my $constant (@{$interface->constants}) { - my $reflect = $constant->extendedAttributes->{"Reflect"}; - my $name = $reflect ? $reflect : $constant->name; - my $value = $constant->value; - my $conditional = $constant->extendedAttributes->{"Conditional"}; - - if ($conditional) { - my $conditionalString = $generator->GenerateConditionalStringFromAttributeValue($conditional); - push(@checks, "#if ${conditionalString}\n"); - } - if ($constant->extendedAttributes->{"ImplementedBy"}) { - push(@checks, "COMPILE_ASSERT($value == " . $constant->extendedAttributes->{"ImplementedBy"} . "::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); - } else { - push(@checks, "COMPILE_ASSERT($value == ${interfaceName}::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); - } + return () if $interface->extendedAttributes->{"DoNotCheckConstants"} || !@{$interface->constants}; - if ($conditional) { - push(@checks, "#endif\n"); - } - } - push(@checks, "\n"); + my $baseScope = $interface->extendedAttributes->{"ConstantsScope"} || $interface->type->name; + + my @checks = (); + foreach my $constant (@{$interface->constants}) { + my $scope = $constant->extendedAttributes->{"ImplementedBy"} || $baseScope; + my $name = $constant->extendedAttributes->{"Reflect"} || $constant->name; + my $value = $constant->value; + my $conditional = $constant->extendedAttributes->{"Conditional"}; + push(@checks, "#if " . $generator->GenerateConditionalStringFromAttributeValue($conditional) . "\n") if $conditional; + push(@checks, "static_assert(${scope}::${name} == ${value}, \"${name} in ${scope} does not match value from IDL\");\n"); + push(@checks, "#endif\n") if $conditional; } + push(@checks, "\n"); return @checks; } @@ -733,23 +1128,22 @@ sub ExtendedAttributeContains # should use the real interface name in the IDL files and then use ImplementedAs to map this to the implementation name. sub GetVisibleInterfaceName { - my $object = shift; - my $interface = shift; + my ($object, $interface) = @_; + my $interfaceName = $interface->extendedAttributes->{"InterfaceName"}; - return $interfaceName ? $interfaceName : $interface->name; + return $interfaceName ? $interfaceName : $interface->type->name; } sub InheritsInterface { - my $object = shift; - my $interface = shift; - my $interfaceName = shift; - my $found = 0; + my ($object, $interface, $interfaceName) = @_; - return 1 if $interfaceName eq $interface->name; + return 1 if $interfaceName eq $interface->type->name; + + my $found = 0; $object->ForAllParents($interface, sub { my $currentInterface = shift; - if ($currentInterface->name eq $interfaceName) { + if ($currentInterface->type->name eq $interfaceName) { $found = 1; } return 1 if $found; @@ -760,12 +1154,11 @@ sub InheritsInterface sub InheritsExtendedAttribute { - my $object = shift; - my $interface = shift; - my $extendedAttribute = shift; - my $found = 0; + my ($object, $interface, $extendedAttribute) = @_; return 1 if $interface->extendedAttributes->{$extendedAttribute}; + + my $found = 0; $object->ForAllParents($interface, sub { my $currentInterface = shift; if ($currentInterface->extendedAttributes->{$extendedAttribute}) { @@ -777,4 +1170,5 @@ sub InheritsExtendedAttribute return $found; } + 1; |