1# 2# WebKit IDL parser 3# 4# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org> 5# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> 6# Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 7# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au> 8# Copyright (C) Research In Motion Limited 2010. All rights reserved. 9# Copyright (C) 2013 Samsung Electronics. All rights reserved. 10# 11# This library is free software; you can redistribute it and/or 12# modify it under the terms of the GNU Library General Public 13# License as published by the Free Software Foundation; either 14# version 2 of the License, or (at your option) any later version. 15# 16# This library is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19# Library General Public License for more details. 20# 21# You should have received a copy of the GNU Library General Public License 22# along with this library; see the file COPYING.LIB. If not, write to 23# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 24# Boston, MA 02110-1301, USA. 25# 26 27package CodeGenerator; 28 29use strict; 30 31use File::Find; 32 33my $useDocument = ""; 34my $useGenerator = ""; 35my $useOutputDir = ""; 36my $useOutputHeadersDir = ""; 37my $useDirectories = ""; 38my $useLayerOnTop = 0; 39my $preprocessor; 40my $writeDependencies = 0; 41my $defines = ""; 42my $targetIdlFilePath = ""; 43 44my $codeGenerator = 0; 45 46my $verbose = 0; 47 48my %numericTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1, 49 "unsigned int" => 1, "unsigned short" => 1, 50 "unsigned long" => 1, "unsigned long long" => 1, 51 "float" => 1, "double" => 1, "byte" => 1, 52 "octet" => 1); 53 54my %primitiveTypeHash = ( "boolean" => 1, "void" => 1, "Date" => 1); 55 56my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1); 57 58# WebCore types used directly in IDL files. 59my %webCoreTypeHash = ( 60 "CompareHow" => 1, 61 "SerializedScriptValue" => 1, 62 "Dictionary" => 1 63); 64 65my %enumTypeHash = (); 66 67my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1); 68 69my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1, 70 "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1, 71 "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1, 72 "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1, 73 "SVGAnimatedPreserveAspectRatio" => 1, 74 "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1, 75 "SVGAnimatedTransformList" => 1); 76 77my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1, 78 "onerror" => 1, "onload" => 1, "onmousedown" => 1, 79 "onmouseenter" => 1, "onmouseleave" => 1, 80 "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1, 81 "onmouseup" => 1, "onresize" => 1, "onscroll" => 1, 82 "onunload" => 1); 83 84my %svgTypeNeedingTearOff = ( 85 "SVGAngle" => "SVGPropertyTearOff<SVGAngle>", 86 "SVGLength" => "SVGPropertyTearOff<SVGLength>", 87 "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>", 88 "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>", 89 "SVGNumber" => "SVGPropertyTearOff<float>", 90 "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>", 91 "SVGPathSegList" => "SVGPathSegListPropertyTearOff", 92 "SVGPoint" => "SVGPropertyTearOff<FloatPoint>", 93 "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>", 94 "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>", 95 "SVGRect" => "SVGPropertyTearOff<FloatRect>", 96 "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>", 97 "SVGTransform" => "SVGPropertyTearOff<SVGTransform>", 98 "SVGTransformList" => "SVGTransformListPropertyTearOff" 99); 100 101my %svgTypeWithWritablePropertiesNeedingTearOff = ( 102 "SVGPoint" => 1, 103 "SVGMatrix" => 1 104); 105 106# Cache of IDL file pathnames. 107my $idlFiles; 108my $cachedInterfaces = {}; 109 110# Default constructor 111sub new 112{ 113 my $object = shift; 114 my $reference = { }; 115 116 $useDirectories = shift; 117 $useGenerator = shift; 118 $useOutputDir = shift; 119 $useOutputHeadersDir = shift; 120 $useLayerOnTop = shift; 121 $preprocessor = shift; 122 $writeDependencies = shift; 123 $verbose = shift; 124 $targetIdlFilePath = shift; 125 126 bless($reference, $object); 127 return $reference; 128} 129 130sub ProcessDocument 131{ 132 my $object = shift; 133 $useDocument = shift; 134 $defines = shift; 135 136 my $ifaceName = "CodeGenerator" . $useGenerator; 137 require $ifaceName . ".pm"; 138 139 %enumTypeHash = map { $_->name => $_->values } @{$useDocument->enumerations}; 140 141 # Dynamically load external code generation perl module 142 $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose, $targetIdlFilePath); 143 unless (defined($codeGenerator)) { 144 my $interfaces = $useDocument->interfaces; 145 foreach my $interface (@$interfaces) { 146 print "Skipping $useGenerator code generation for IDL interface \"" . $interface->name . "\".\n" if $verbose; 147 } 148 return; 149 } 150 151 my $interfaces = $useDocument->interfaces; 152 foreach my $interface (@$interfaces) { 153 print "Generating $useGenerator bindings code for IDL interface \"" . $interface->name . "\"...\n" if $verbose; 154 $codeGenerator->GenerateInterface($interface, $defines); 155 $codeGenerator->WriteData($interface, $useOutputDir, $useOutputHeadersDir); 156 } 157} 158 159sub FileNamePrefix 160{ 161 my $object = shift; 162 163 my $ifaceName = "CodeGenerator" . $useGenerator; 164 require $ifaceName . ".pm"; 165 166 # Dynamically load external code generation perl module 167 $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose); 168 return $codeGenerator->FileNamePrefix(); 169} 170 171sub UpdateFile 172{ 173 my $object = shift; 174 my $fileName = shift; 175 my $contents = shift; 176 177 open FH, "> $fileName" or die "Couldn't open $fileName: $!\n"; 178 print FH $contents; 179 close FH; 180} 181 182sub ForAllParents 183{ 184 my $object = shift; 185 my $interface = shift; 186 my $beforeRecursion = shift; 187 my $afterRecursion = shift; 188 189 my $recurse; 190 $recurse = sub { 191 my $currentInterface = shift; 192 193 for (@{$currentInterface->parents}) { 194 my $interfaceName = $_; 195 my $parentInterface = $object->ParseInterface($interfaceName); 196 197 if ($beforeRecursion) { 198 &$beforeRecursion($parentInterface) eq 'prune' and next; 199 } 200 &$recurse($parentInterface); 201 &$afterRecursion($parentInterface) if $afterRecursion; 202 } 203 }; 204 205 &$recurse($interface); 206} 207 208sub AddMethodsConstantsAndAttributesFromParentInterfaces 209{ 210 # Add to $interface all of its inherited interface members, except for those 211 # inherited through $interface's first listed parent. If an array reference 212 # is passed in as $parents, the names of all ancestor interfaces visited 213 # will be appended to the array. If $collectDirectParents is true, then 214 # even the names of $interface's first listed parent and its ancestors will 215 # be appended to $parents. 216 217 my $object = shift; 218 my $interface = shift; 219 my $parents = shift; 220 my $collectDirectParents = shift; 221 222 my $first = 1; 223 224 $object->ForAllParents($interface, sub { 225 my $currentInterface = shift; 226 227 if ($first) { 228 # Ignore first parent class, already handled by the generation itself. 229 $first = 0; 230 231 if ($collectDirectParents) { 232 # Just collect the names of the direct ancestor interfaces, 233 # if necessary. 234 push(@$parents, $currentInterface->name); 235 $object->ForAllParents($currentInterface, sub { 236 my $currentInterface = shift; 237 push(@$parents, $currentInterface->name); 238 }, undef); 239 } 240 241 # Prune the recursion here. 242 return 'prune'; 243 } 244 245 # Collect the name of this additional parent. 246 push(@$parents, $currentInterface->name) if $parents; 247 248 print " | |> -> Inheriting " 249 . @{$currentInterface->constants} . " constants, " 250 . @{$currentInterface->functions} . " functions, " 251 . @{$currentInterface->attributes} . " attributes...\n | |>\n" if $verbose; 252 253 # Add this parent's members to $interface. 254 push(@{$interface->constants}, @{$currentInterface->constants}); 255 push(@{$interface->functions}, @{$currentInterface->functions}); 256 push(@{$interface->attributes}, @{$currentInterface->attributes}); 257 }); 258} 259 260sub FindSuperMethod 261{ 262 my ($object, $interface, $functionName) = @_; 263 my $indexer; 264 $object->ForAllParents($interface, undef, sub { 265 my $currentInterface = shift; 266 foreach my $function (@{$currentInterface->functions}) { 267 if ($function->signature->name eq $functionName) { 268 $indexer = $function->signature; 269 return 'prune'; 270 } 271 } 272 }); 273 return $indexer; 274} 275 276sub IDLFileForInterface 277{ 278 my $object = shift; 279 my $interfaceName = shift; 280 281 unless ($idlFiles) { 282 my $sourceRoot = $ENV{SOURCE_ROOT}; 283 my @directories = map { $_ = "$sourceRoot/$_" if $sourceRoot && -d "$sourceRoot/$_"; $_ } @$useDirectories; 284 push(@directories, "."); 285 286 $idlFiles = { }; 287 288 my $wanted = sub { 289 $idlFiles->{$1} = $File::Find::name if /^([A-Z].*)\.idl$/; 290 $File::Find::prune = 1 if /^\../; 291 }; 292 find($wanted, @directories); 293 } 294 295 return $idlFiles->{$interfaceName}; 296} 297 298sub ParseInterface 299{ 300 my $object = shift; 301 my $interfaceName = shift; 302 303 return undef if $interfaceName eq 'Object'; 304 305 if (exists $cachedInterfaces->{$interfaceName}) { 306 return $cachedInterfaces->{$interfaceName}; 307 } 308 309 # Step #1: Find the IDL file associated with 'interface' 310 my $filename = $object->IDLFileForInterface($interfaceName) 311 or die("Could NOT find IDL file for interface \"$interfaceName\"!\n"); 312 313 print " | |> Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose; 314 315 # Step #2: Parse the found IDL file (in quiet mode). 316 my $parser = IDLParser->new(1); 317 my $document = $parser->Parse($filename, $defines, $preprocessor); 318 319 foreach my $interface (@{$document->interfaces}) { 320 if ($interface->name eq $interfaceName) { 321 $cachedInterfaces->{$interfaceName} = $interface; 322 return $interface; 323 } 324 } 325 326 die("Could NOT find interface definition for $interfaceName in $filename"); 327} 328 329# Helpers for all CodeGenerator***.pm modules 330 331sub SkipIncludeHeader 332{ 333 my $object = shift; 334 my $type = shift; 335 336 return 1 if $object->IsPrimitiveType($type); 337 338 # Special case: SVGPoint.h / SVGNumber.h do not exist. 339 return 1 if $type eq "SVGPoint" or $type eq "SVGNumber"; 340 return 0; 341} 342 343sub IsConstructorTemplate 344{ 345 my $object = shift; 346 my $interface = shift; 347 my $template = shift; 348 349 return $interface->extendedAttributes->{"ConstructorTemplate"} && $interface->extendedAttributes->{"ConstructorTemplate"} eq $template; 350} 351 352sub IsNumericType 353{ 354 my $object = shift; 355 my $type = shift; 356 357 return 1 if $numericTypeHash{$type}; 358 return 0; 359} 360 361sub IsPrimitiveType 362{ 363 my $object = shift; 364 my $type = shift; 365 366 return 1 if $primitiveTypeHash{$type}; 367 return 1 if $numericTypeHash{$type}; 368 return 0; 369} 370 371sub IsStringType 372{ 373 my $object = shift; 374 my $type = shift; 375 376 return 1 if $stringTypeHash{$type}; 377 return 0; 378} 379 380sub IsEnumType 381{ 382 my $object = shift; 383 my $type = shift; 384 385 return 1 if exists $enumTypeHash{$type}; 386 return 0; 387} 388 389sub ValidEnumValues 390{ 391 my $object = shift; 392 my $type = shift; 393 394 return @{$enumTypeHash{$type}}; 395} 396 397sub IsNonPointerType 398{ 399 my $object = shift; 400 my $type = shift; 401 402 return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type} or $numericTypeHash{$type}; 403 return 0; 404} 405 406sub IsSVGTypeNeedingTearOff 407{ 408 my $object = shift; 409 my $type = shift; 410 411 return 1 if exists $svgTypeNeedingTearOff{$type}; 412 return 0; 413} 414 415sub IsSVGTypeWithWritablePropertiesNeedingTearOff 416{ 417 my $object = shift; 418 my $type = shift; 419 420 return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type}; 421 return 0; 422} 423 424sub IsTypedArrayType 425{ 426 my $object = shift; 427 my $type = shift; 428 return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView")); 429 return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array")); 430 return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array")); 431 return 1 if (($type eq "Float32Array") or ($type eq "Float64Array")); 432 return 0; 433} 434 435sub IsRefPtrType 436{ 437 my $object = shift; 438 my $type = shift; 439 440 return 0 if $object->IsPrimitiveType($type); 441 return 0 if $object->GetArrayType($type); 442 return 0 if $object->GetSequenceType($type); 443 return 0 if $type eq "DOMString"; 444 return 0 if $object->IsEnumType($type); 445 446 return 1; 447} 448 449sub GetSVGTypeNeedingTearOff 450{ 451 my $object = shift; 452 my $type = shift; 453 454 return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type}; 455 return undef; 456} 457 458sub GetSVGWrappedTypeNeedingTearOff 459{ 460 my $object = shift; 461 my $type = shift; 462 463 my $svgTypeNeedingTearOff = $object->GetSVGTypeNeedingTearOff($type); 464 return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff; 465 466 if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) { 467 $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//; 468 } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) { 469 $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//; 470 } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) { 471 $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//; 472 } elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) { 473 $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//; 474 } 475 476 $svgTypeNeedingTearOff =~ s/>//; 477 return $svgTypeNeedingTearOff; 478} 479 480sub IsSVGAnimatedType 481{ 482 my $object = shift; 483 my $type = shift; 484 485 return 1 if $svgAnimatedTypeHash{$type}; 486 return 0; 487} 488 489sub GetSequenceType 490{ 491 my $object = shift; 492 my $type = shift; 493 494 return $1 if $type =~ /^sequence<([\w\d_\s]+)>.*/; 495 return ""; 496} 497 498sub GetArrayType 499{ 500 my $object = shift; 501 my $type = shift; 502 503 return $1 if $type =~ /^([\w\d_\s]+)\[\]/; 504 return ""; 505} 506 507sub AssertNotSequenceType 508{ 509 my $object = shift; 510 my $type = shift; 511 die "Sequences must not be used as the type of an attribute, constant or exception field." if $object->GetSequenceType($type); 512} 513 514# Uppercase the first letter while respecting WebKit style guidelines. 515# E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. 516sub WK_ucfirst 517{ 518 my ($object, $param) = @_; 519 my $ret = ucfirst($param); 520 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; 521 522 return $ret; 523} 524 525# Lowercase the first letter while respecting WebKit style guidelines. 526# URL becomes url, but SetURL becomes setURL. 527sub WK_lcfirst 528{ 529 my ($object, $param) = @_; 530 my $ret = lcfirst($param); 531 $ret =~ s/hTML/html/ if $ret =~ /^hTML/; 532 $ret =~ s/uRL/url/ if $ret =~ /^uRL/; 533 $ret =~ s/jS/js/ if $ret =~ /^jS/; 534 $ret =~ s/xML/xml/ if $ret =~ /^xML/; 535 $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/; 536 $ret =~ s/cSS/css/ if $ret =~ /^cSS/; 537 538 # For HTML5 FileSystem API Flags attributes. 539 # (create is widely used to instantiate an object and must be avoided.) 540 $ret =~ s/^create/isCreate/ if $ret =~ /^create$/; 541 $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/; 542 543 return $ret; 544} 545 546# Return the C++ namespace that a given attribute name string is defined in. 547sub NamespaceForAttributeName 548{ 549 my ($object, $interfaceName, $attributeName) = @_; 550 return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName}; 551 return "HTMLNames"; 552} 553 554# Identifies overloaded functions and for each function adds an array with 555# links to its respective overloads (including itself). 556sub LinkOverloadedFunctions 557{ 558 my ($object, $interface) = @_; 559 560 my %nameToFunctionsMap = (); 561 foreach my $function (@{$interface->functions}) { 562 my $name = $function->signature->name; 563 $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name}; 564 push(@{$nameToFunctionsMap{$name}}, $function); 565 $function->{overloads} = $nameToFunctionsMap{$name}; 566 $function->{overloadIndex} = @{$nameToFunctionsMap{$name}}; 567 } 568} 569 570sub AttributeNameForGetterAndSetter 571{ 572 my ($generator, $attribute) = @_; 573 574 my $attributeName = $attribute->signature->name; 575 if ($attribute->signature->extendedAttributes->{"ImplementedAs"}) { 576 $attributeName = $attribute->signature->extendedAttributes->{"ImplementedAs"}; 577 } 578 my $attributeType = $attribute->signature->type; 579 580 # Avoid clash with C++ keyword. 581 $attributeName = "_operator" if $attributeName eq "operator"; 582 583 # SVGAElement defines a non-virtual "String& target() const" method which clashes with "virtual String target() const" in Element. 584 # To solve this issue the SVGAElement method was renamed to "svgTarget", take care of that when calling this method. 585 $attributeName = "svgTarget" if $attributeName eq "target" and $attributeType eq "SVGAnimatedString"; 586 587 # SVG animated types need to use a special attribute name. 588 # The rest of the special casing for SVG animated types is handled in the language-specific code generators. 589 $attributeName .= "Animated" if $generator->IsSVGAnimatedType($attributeType); 590 591 return $attributeName; 592} 593 594sub ContentAttributeName 595{ 596 my ($generator, $implIncludes, $interfaceName, $attribute) = @_; 597 598 my $contentAttributeName = $attribute->signature->extendedAttributes->{"Reflect"}; 599 return undef if !$contentAttributeName; 600 601 $contentAttributeName = lc $generator->AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "VALUE_IS_MISSING"; 602 603 my $namespace = $generator->NamespaceForAttributeName($interfaceName, $contentAttributeName); 604 605 $implIncludes->{"${namespace}.h"} = 1; 606 return "WebCore::${namespace}::${contentAttributeName}Attr"; 607} 608 609sub CanUseFastAttribute 610{ 611 my ($generator, $attribute) = @_; 612 my $attributeType = $attribute->signature->type; 613 # HTMLNames::styleAttr cannot be used with fast{Get,Has}Attribute but we do not [Reflect] the 614 # style attribute. 615 616 return !$generator->IsSVGAnimatedType($attributeType); 617} 618 619sub GetterExpression 620{ 621 my ($generator, $implIncludes, $interfaceName, $attribute) = @_; 622 623 my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute); 624 625 if (!$contentAttributeName) { 626 return ($generator->WK_lcfirst($generator->AttributeNameForGetterAndSetter($attribute))); 627 } 628 629 my $functionName; 630 if ($attribute->signature->extendedAttributes->{"URL"}) { 631 $functionName = "getURLAttribute"; 632 } elsif ($attribute->signature->type eq "boolean") { 633 my $namespace = $generator->NamespaceForAttributeName($interfaceName, $contentAttributeName); 634 if ($generator->CanUseFastAttribute($attribute)) { 635 $functionName = "fastHasAttribute"; 636 } else { 637 $functionName = "hasAttribute"; 638 } 639 } elsif ($attribute->signature->type eq "long") { 640 $functionName = "getIntegralAttribute"; 641 } elsif ($attribute->signature->type eq "unsigned long") { 642 $functionName = "getUnsignedIntegralAttribute"; 643 } else { 644 if ($contentAttributeName eq "WebCore::HTMLNames::idAttr") { 645 $functionName = "getIdAttribute"; 646 $contentAttributeName = ""; 647 } elsif ($contentAttributeName eq "WebCore::HTMLNames::nameAttr") { 648 $functionName = "getNameAttribute"; 649 $contentAttributeName = ""; 650 } elsif ($generator->CanUseFastAttribute($attribute)) { 651 $functionName = "fastGetAttribute"; 652 } else { 653 $functionName = "getAttribute"; 654 } 655 } 656 657 return ($functionName, $contentAttributeName); 658} 659 660sub SetterExpression 661{ 662 my ($generator, $implIncludes, $interfaceName, $attribute) = @_; 663 664 my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute); 665 666 if (!$contentAttributeName) { 667 return ("set" . $generator->WK_ucfirst($generator->AttributeNameForGetterAndSetter($attribute))); 668 } 669 670 my $functionName; 671 if ($attribute->signature->type eq "boolean") { 672 $functionName = "setBooleanAttribute"; 673 } elsif ($attribute->signature->type eq "long") { 674 $functionName = "setIntegralAttribute"; 675 } elsif ($attribute->signature->type eq "unsigned long") { 676 $functionName = "setUnsignedIntegralAttribute"; 677 } else { 678 $functionName = "setAttribute"; 679 } 680 681 return ($functionName, $contentAttributeName); 682} 683 684sub IsWrapperType 685{ 686 my $object = shift; 687 my $type = shift; 688 689 return 0 if $object->IsPrimitiveType($type); 690 return 0 if $object->GetArrayType($type); 691 return 0 if $object->GetSequenceType($type); 692 return 0 if $object->IsEnumType($type); 693 return 0 if $object->IsStringType($type); 694 return 0 if $webCoreTypeHash{$type}; 695 return 0 if $type eq "any"; 696 697 return 1; 698} 699 700sub IsCallbackInterface 701{ 702 my $object = shift; 703 my $type = shift; 704 705 return 0 unless $object->IsWrapperType($type); 706 707 my $idlFile = $object->IDLFileForInterface($type) 708 or die("Could NOT find IDL file for interface \"$type\"!\n"); 709 710 open FILE, "<", $idlFile; 711 my @lines = <FILE>; 712 close FILE; 713 714 my $fileContents = join('', @lines); 715 return ($fileContents =~ /callback\s+interface\s+(\w+)/gs); 716} 717 718sub GenerateConditionalString 719{ 720 my $generator = shift; 721 my $node = shift; 722 723 my $conditional = $node->extendedAttributes->{"Conditional"}; 724 if ($conditional) { 725 return $generator->GenerateConditionalStringFromAttributeValue($conditional); 726 } else { 727 return ""; 728 } 729} 730 731sub GenerateConstructorConditionalString 732{ 733 my $generator = shift; 734 my $node = shift; 735 736 my $conditional = $node->extendedAttributes->{"ConstructorConditional"}; 737 if ($conditional) { 738 return $generator->GenerateConditionalStringFromAttributeValue($conditional); 739 } else { 740 return ""; 741 } 742} 743 744sub GenerateConditionalStringFromAttributeValue 745{ 746 my $generator = shift; 747 my $conditional = shift; 748 749 my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : '')); 750 if ($operator) { 751 # Avoid duplicated conditions. 752 my %conditions; 753 map { $conditions{$_} = 1 } split('\\' . $operator, $conditional); 754 return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")"; 755 } else { 756 return "ENABLE(" . $conditional . ")"; 757 } 758} 759 760sub GenerateCompileTimeCheckForEnumsIfNeeded 761{ 762 my ($generator, $interface) = @_; 763 my $interfaceName = $interface->name; 764 my @checks = (); 765 # If necessary, check that all constants are available as enums with the same value. 766 if (!$interface->extendedAttributes->{"DoNotCheckConstants"} && @{$interface->constants}) { 767 push(@checks, "\n"); 768 foreach my $constant (@{$interface->constants}) { 769 my $reflect = $constant->extendedAttributes->{"Reflect"}; 770 my $name = $reflect ? $reflect : $constant->name; 771 my $value = $constant->value; 772 my $conditional = $constant->extendedAttributes->{"Conditional"}; 773 774 if ($conditional) { 775 my $conditionalString = $generator->GenerateConditionalStringFromAttributeValue($conditional); 776 push(@checks, "#if ${conditionalString}\n"); 777 } 778 779 if ($constant->extendedAttributes->{"ImplementedBy"}) { 780 push(@checks, "COMPILE_ASSERT($value == " . $constant->extendedAttributes->{"ImplementedBy"} . "::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); 781 } else { 782 push(@checks, "COMPILE_ASSERT($value == ${interfaceName}::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); 783 } 784 785 if ($conditional) { 786 push(@checks, "#endif\n"); 787 } 788 } 789 push(@checks, "\n"); 790 } 791 return @checks; 792} 793 794sub ExtendedAttributeContains 795{ 796 my $object = shift; 797 my $callWith = shift; 798 return 0 unless $callWith; 799 my $keyword = shift; 800 801 my @callWithKeywords = split /\s*\|\s*/, $callWith; 802 return grep { $_ eq $keyword } @callWithKeywords; 803} 804 805# FIXME: This is backwards. We currently name the interface and the IDL files with the implementation name. We 806# should use the real interface name in the IDL files and then use ImplementedAs to map this to the implementation name. 807sub GetVisibleInterfaceName 808{ 809 my $object = shift; 810 my $interface = shift; 811 my $interfaceName = $interface->extendedAttributes->{"InterfaceName"}; 812 return $interfaceName ? $interfaceName : $interface->name; 813} 814 815sub InheritsInterface 816{ 817 my $object = shift; 818 my $interface = shift; 819 my $interfaceName = shift; 820 my $found = 0; 821 822 return 1 if $interfaceName eq $interface->name; 823 $object->ForAllParents($interface, sub { 824 my $currentInterface = shift; 825 if ($currentInterface->name eq $interfaceName) { 826 $found = 1; 827 } 828 return 1 if $found; 829 }, 0); 830 831 return $found; 832} 833 834sub InheritsExtendedAttribute 835{ 836 my $object = shift; 837 my $interface = shift; 838 my $extendedAttribute = shift; 839 my $found = 0; 840 841 return 1 if $interface->extendedAttributes->{$extendedAttribute}; 842 $object->ForAllParents($interface, sub { 843 my $currentInterface = shift; 844 if ($currentInterface->extendedAttributes->{$extendedAttribute}) { 845 $found = 1; 846 } 847 return 1 if $found; 848 }, 0); 849 850 return $found; 851} 852 8531; 854