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, 52 "unrestricted float" => 1, "unrestricted double" => 1, 53 "byte" => 1, "octet" => 1); 54 55my %primitiveTypeHash = ( "boolean" => 1, "void" => 1, "Date" => 1); 56 57my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1); 58 59# WebCore types used directly in IDL files. 60my %webCoreTypeHash = ( 61 "CompareHow" => 1, 62 "SerializedScriptValue" => 1, 63 "Dictionary" => 1 64); 65 66my %enumTypeHash = (); 67 68my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1); 69 70my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1, 71 "onerror" => 1, "onload" => 1, "onmousedown" => 1, 72 "onmouseenter" => 1, "onmouseleave" => 1, 73 "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1, 74 "onmouseup" => 1, "onresize" => 1, "onscroll" => 1, 75 "onunload" => 1); 76 77my %svgTypeNeedingTearOff = ( 78 "SVGAngle" => "SVGPropertyTearOff<SVGAngle>", 79 "SVGLength" => "SVGPropertyTearOff<SVGLength>", 80 "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>", 81 "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>", 82 "SVGNumber" => "SVGPropertyTearOff<float>", 83 "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>", 84 "SVGPathSegList" => "SVGPathSegListPropertyTearOff", 85 "SVGPoint" => "SVGPropertyTearOff<SVGPoint>", 86 "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>", 87 "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>", 88 "SVGRect" => "SVGPropertyTearOff<FloatRect>", 89 "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>", 90 "SVGTransform" => "SVGPropertyTearOff<SVGTransform>", 91 "SVGTransformList" => "SVGTransformListPropertyTearOff" 92); 93 94my %svgTypeWithWritablePropertiesNeedingTearOff = ( 95 "SVGPoint" => 1, 96 "SVGMatrix" => 1 97); 98 99# Cache of IDL file pathnames. 100my $idlFiles; 101my $cachedInterfaces = {}; 102 103# Default constructor 104sub new 105{ 106 my $object = shift; 107 my $reference = { }; 108 109 $useDirectories = shift; 110 $useGenerator = shift; 111 $useOutputDir = shift; 112 $useOutputHeadersDir = shift; 113 $useLayerOnTop = shift; 114 $preprocessor = shift; 115 $writeDependencies = shift; 116 $verbose = shift; 117 $targetIdlFilePath = shift; 118 119 bless($reference, $object); 120 return $reference; 121} 122 123sub ProcessDocument 124{ 125 my $object = shift; 126 $useDocument = shift; 127 $defines = shift; 128 129 my $ifaceName = "CodeGenerator" . $useGenerator; 130 require $ifaceName . ".pm"; 131 132 %enumTypeHash = map { $_->name => $_->values } @{$useDocument->enumerations}; 133 134 # Dynamically load external code generation perl module 135 $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose, $targetIdlFilePath); 136 unless (defined($codeGenerator)) { 137 my $interfaces = $useDocument->interfaces; 138 foreach my $interface (@$interfaces) { 139 print "Skipping $useGenerator code generation for IDL interface \"" . $interface->name . "\".\n" if $verbose; 140 } 141 return; 142 } 143 144 my $interfaces = $useDocument->interfaces; 145 foreach my $interface (@$interfaces) { 146 print "Generating $useGenerator bindings code for IDL interface \"" . $interface->name . "\"...\n" if $verbose; 147 $codeGenerator->GenerateInterface($interface, $defines); 148 $codeGenerator->WriteData($interface, $useOutputDir, $useOutputHeadersDir); 149 } 150} 151 152sub FileNamePrefix 153{ 154 my $object = shift; 155 156 my $ifaceName = "CodeGenerator" . $useGenerator; 157 require $ifaceName . ".pm"; 158 159 # Dynamically load external code generation perl module 160 $codeGenerator = $ifaceName->new($object, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose); 161 return $codeGenerator->FileNamePrefix(); 162} 163 164sub UpdateFile 165{ 166 my $object = shift; 167 my $fileName = shift; 168 my $contents = shift; 169 170 open FH, "> $fileName" or die "Couldn't open $fileName: $!\n"; 171 print FH $contents; 172 close FH; 173} 174 175sub ForAllParents 176{ 177 my $object = shift; 178 my $interface = shift; 179 my $beforeRecursion = shift; 180 my $afterRecursion = shift; 181 182 my $recurse; 183 $recurse = sub { 184 my $outerInterface = shift; 185 my $currentInterface = shift; 186 187 for (@{$currentInterface->parents}) { 188 my $interfaceName = $_; 189 my $parentInterface = $object->ParseInterface($outerInterface, $interfaceName); 190 191 if ($beforeRecursion) { 192 &$beforeRecursion($parentInterface) eq 'prune' and next; 193 } 194 &$recurse($outerInterface, $parentInterface); 195 &$afterRecursion($parentInterface) if $afterRecursion; 196 } 197 }; 198 199 &$recurse($interface, $interface); 200} 201 202sub FindSuperMethod 203{ 204 my ($object, $interface, $functionName) = @_; 205 my $indexer; 206 $object->ForAllParents($interface, undef, sub { 207 my $currentInterface = shift; 208 foreach my $function (@{$currentInterface->functions}) { 209 if ($function->signature->name eq $functionName) { 210 $indexer = $function->signature; 211 return 'prune'; 212 } 213 } 214 }); 215 return $indexer; 216} 217 218sub IDLFileForInterface 219{ 220 my $object = shift; 221 my $interfaceName = shift; 222 223 unless ($idlFiles) { 224 my $sourceRoot = $ENV{SOURCE_ROOT}; 225 my @directories = map { $_ = "$sourceRoot/$_" if $sourceRoot && -d "$sourceRoot/$_"; $_ } @$useDirectories; 226 push(@directories, "."); 227 228 $idlFiles = { }; 229 230 my $wanted = sub { 231 $idlFiles->{$1} = $File::Find::name if /^([A-Z].*)\.idl$/; 232 $File::Find::prune = 1 if /^\../; 233 }; 234 find($wanted, @directories); 235 } 236 237 return $idlFiles->{$interfaceName}; 238} 239 240sub ParseInterface 241{ 242 my $object = shift; 243 my $outerInterface = shift; 244 my $interfaceName = shift; 245 246 return undef if $interfaceName eq 'Object'; 247 248 if (exists $cachedInterfaces->{$interfaceName}) { 249 return $cachedInterfaces->{$interfaceName}; 250 } 251 252 # Step #1: Find the IDL file associated with 'interface' 253 my $filename = $object->IDLFileForInterface($interfaceName) 254 or die("Could NOT find IDL file for interface \"$interfaceName\", reachable from \"" . $outerInterface->name . "\"!\n"); 255 256 print " | |> Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose; 257 258 # Step #2: Parse the found IDL file (in quiet mode). 259 my $parser = IDLParser->new(1); 260 my $document = $parser->Parse($filename, $defines, $preprocessor); 261 262 foreach my $interface (@{$document->interfaces}) { 263 if ($interface->name eq $interfaceName) { 264 $cachedInterfaces->{$interfaceName} = $interface; 265 return $interface; 266 } 267 } 268 269 die("Could NOT find interface definition for $interfaceName in $filename"); 270} 271 272# Helpers for all CodeGenerator***.pm modules 273 274sub SkipIncludeHeader 275{ 276 my $object = shift; 277 my $type = shift; 278 279 return 1 if $object->IsPrimitiveType($type); 280 281 # Special case: SVGNumber.h does not exist. 282 return 1 if $type eq "SVGNumber"; 283 284 # Typed arrays already included by JSDOMBinding.h. 285 return 1 if $object->IsTypedArrayType($type); 286 287 return 0; 288} 289 290sub IsConstructorTemplate 291{ 292 my $object = shift; 293 my $interface = shift; 294 my $template = shift; 295 296 return $interface->extendedAttributes->{"ConstructorTemplate"} && $interface->extendedAttributes->{"ConstructorTemplate"} eq $template; 297} 298 299sub IsNumericType 300{ 301 my $object = shift; 302 my $type = shift; 303 304 return 1 if $numericTypeHash{$type}; 305 return 0; 306} 307 308sub IsPrimitiveType 309{ 310 my $object = shift; 311 my $type = shift; 312 313 return 1 if $primitiveTypeHash{$type}; 314 return 1 if $numericTypeHash{$type}; 315 return 0; 316} 317 318sub IsStringType 319{ 320 my $object = shift; 321 my $type = shift; 322 323 return 1 if $stringTypeHash{$type}; 324 return 0; 325} 326 327sub IsEnumType 328{ 329 my $object = shift; 330 my $type = shift; 331 332 return 1 if exists $enumTypeHash{$type}; 333 return 0; 334} 335 336sub ValidEnumValues 337{ 338 my $object = shift; 339 my $type = shift; 340 341 return @{$enumTypeHash{$type}}; 342} 343 344sub IsNonPointerType 345{ 346 my $object = shift; 347 my $type = shift; 348 349 return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type} or $numericTypeHash{$type}; 350 return 0; 351} 352 353sub IsSVGTypeNeedingTearOff 354{ 355 my $object = shift; 356 my $type = shift; 357 358 return 1 if exists $svgTypeNeedingTearOff{$type}; 359 return 0; 360} 361 362sub IsSVGTypeWithWritablePropertiesNeedingTearOff 363{ 364 my $object = shift; 365 my $type = shift; 366 367 return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type}; 368 return 0; 369} 370 371sub IsTypedArrayType 372{ 373 my $object = shift; 374 my $type = shift; 375 return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView")); 376 return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array")); 377 return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array")); 378 return 1 if (($type eq "Float32Array") or ($type eq "Float64Array") or ($type eq "DataView")); 379 return 0; 380} 381 382sub IsRefPtrType 383{ 384 my $object = shift; 385 my $type = shift; 386 387 return 0 if $object->IsPrimitiveType($type); 388 return 0 if $object->GetArrayType($type); 389 return 0 if $object->GetSequenceType($type); 390 return 0 if $type eq "DOMString"; 391 return 0 if $object->IsEnumType($type); 392 393 return 1; 394} 395 396sub GetSVGTypeNeedingTearOff 397{ 398 my $object = shift; 399 my $type = shift; 400 401 return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type}; 402 return undef; 403} 404 405sub GetSVGWrappedTypeNeedingTearOff 406{ 407 my $object = shift; 408 my $type = shift; 409 410 my $svgTypeNeedingTearOff = $object->GetSVGTypeNeedingTearOff($type); 411 return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff; 412 413 if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) { 414 $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//; 415 } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) { 416 $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//; 417 } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) { 418 $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//; 419 } elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) { 420 $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//; 421 } 422 423 $svgTypeNeedingTearOff =~ s/>//; 424 return $svgTypeNeedingTearOff; 425} 426 427sub IsSVGAnimatedType 428{ 429 my $object = shift; 430 my $type = shift; 431 432 return $type =~ /^SVGAnimated/; 433} 434 435sub GetSequenceType 436{ 437 my $object = shift; 438 my $type = shift; 439 440 return $1 if $type =~ /^sequence<([\w\d_\s]+)>.*/; 441 return ""; 442} 443 444sub GetArrayType 445{ 446 my $object = shift; 447 my $type = shift; 448 449 return $1 if $type =~ /^([\w\d_\s]+)\[\]/; 450 return ""; 451} 452 453sub AssertNotSequenceType 454{ 455 my $object = shift; 456 my $type = shift; 457 die "Sequences must not be used as the type of an attribute, constant or exception field." if $object->GetSequenceType($type); 458} 459 460# Uppercase the first letter while respecting WebKit style guidelines. 461# E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. 462sub WK_ucfirst 463{ 464 my ($object, $param) = @_; 465 my $ret = ucfirst($param); 466 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; 467 $ret =~ s/Svg/SVG/ if $ret =~ /^Svg/; 468 469 return $ret; 470} 471 472# Lowercase the first letter while respecting WebKit style guidelines. 473# URL becomes url, but SetURL becomes setURL. 474sub WK_lcfirst 475{ 476 my ($object, $param) = @_; 477 my $ret = lcfirst($param); 478 $ret =~ s/hTML/html/ if $ret =~ /^hTML/; 479 $ret =~ s/uRL/url/ if $ret =~ /^uRL/; 480 $ret =~ s/jS/js/ if $ret =~ /^jS/; 481 $ret =~ s/xML/xml/ if $ret =~ /^xML/; 482 $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/; 483 $ret =~ s/cSS/css/ if $ret =~ /^cSS/; 484 485 # For HTML5 FileSystem API Flags attributes. 486 # (create is widely used to instantiate an object and must be avoided.) 487 $ret =~ s/^create/isCreate/ if $ret =~ /^create$/; 488 $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/; 489 490 return $ret; 491} 492 493# Return the C++ namespace that a given attribute name string is defined in. 494sub NamespaceForAttributeName 495{ 496 my ($object, $interfaceName, $attributeName) = @_; 497 return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName}; 498 return "HTMLNames"; 499} 500 501# Identifies overloaded functions and for each function adds an array with 502# links to its respective overloads (including itself). 503sub LinkOverloadedFunctions 504{ 505 my ($object, $interface) = @_; 506 507 my %nameToFunctionsMap = (); 508 foreach my $function (@{$interface->functions}) { 509 my $name = $function->signature->name; 510 $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name}; 511 push(@{$nameToFunctionsMap{$name}}, $function); 512 $function->{overloads} = $nameToFunctionsMap{$name}; 513 $function->{overloadIndex} = @{$nameToFunctionsMap{$name}}; 514 } 515} 516 517sub AttributeNameForGetterAndSetter 518{ 519 my ($generator, $attribute) = @_; 520 521 my $attributeName = $attribute->signature->name; 522 if ($attribute->signature->extendedAttributes->{"ImplementedAs"}) { 523 $attributeName = $attribute->signature->extendedAttributes->{"ImplementedAs"}; 524 } 525 my $attributeType = $attribute->signature->type; 526 527 # SVG animated types need to use a special attribute name. 528 # The rest of the special casing for SVG animated types is handled in the language-specific code generators. 529 $attributeName .= "Animated" if $generator->IsSVGAnimatedType($attributeType); 530 531 return $attributeName; 532} 533 534sub ContentAttributeName 535{ 536 my ($generator, $implIncludes, $interfaceName, $attribute) = @_; 537 538 my $contentAttributeName = $attribute->signature->extendedAttributes->{"Reflect"}; 539 return undef if !$contentAttributeName; 540 541 $contentAttributeName = lc $generator->AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "VALUE_IS_MISSING"; 542 543 my $namespace = $generator->NamespaceForAttributeName($interfaceName, $contentAttributeName); 544 545 $implIncludes->{"${namespace}.h"} = 1; 546 return "WebCore::${namespace}::${contentAttributeName}Attr"; 547} 548 549sub GetterExpression 550{ 551 my ($generator, $implIncludes, $interfaceName, $attribute) = @_; 552 553 my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute); 554 555 if (!$contentAttributeName) { 556 return ($generator->WK_lcfirst($generator->AttributeNameForGetterAndSetter($attribute))); 557 } 558 559 my $attributeType = $attribute->signature->type; 560 561 my $functionName; 562 if ($attribute->signature->extendedAttributes->{"URL"}) { 563 $functionName = "getURLAttribute"; 564 } elsif ($attributeType eq "boolean") { 565 $functionName = "fastHasAttribute"; 566 } elsif ($attributeType eq "long") { 567 $functionName = "getIntegralAttribute"; 568 } elsif ($attributeType eq "unsigned long") { 569 $functionName = "getUnsignedIntegralAttribute"; 570 } else { 571 if ($contentAttributeName eq "WebCore::HTMLNames::idAttr") { 572 $functionName = "getIdAttribute"; 573 $contentAttributeName = ""; 574 } elsif ($contentAttributeName eq "WebCore::HTMLNames::nameAttr") { 575 $functionName = "getNameAttribute"; 576 $contentAttributeName = ""; 577 } elsif ($generator->IsSVGAnimatedType($attributeType)) { 578 $functionName = "getAttribute"; 579 } else { 580 $functionName = "fastGetAttribute"; 581 } 582 } 583 584 return ($functionName, $contentAttributeName); 585} 586 587sub SetterExpression 588{ 589 my ($generator, $implIncludes, $interfaceName, $attribute) = @_; 590 591 my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute); 592 593 if (!$contentAttributeName) { 594 return ("set" . $generator->WK_ucfirst($generator->AttributeNameForGetterAndSetter($attribute))); 595 } 596 597 my $attributeType = $attribute->signature->type; 598 599 my $functionName; 600 if ($attributeType eq "boolean") { 601 $functionName = "setBooleanAttribute"; 602 } elsif ($attributeType eq "long") { 603 $functionName = "setIntegralAttribute"; 604 } elsif ($attributeType eq "unsigned long") { 605 $functionName = "setUnsignedIntegralAttribute"; 606 } elsif ($generator->IsSVGAnimatedType($attributeType)) { 607 $functionName = "setAttribute"; 608 } else { 609 $functionName = "setAttributeWithoutSynchronization"; 610 } 611 612 return ($functionName, $contentAttributeName); 613} 614 615sub IsWrapperType 616{ 617 my $object = shift; 618 my $type = shift; 619 620 return 0 if $object->IsPrimitiveType($type); 621 return 0 if $object->GetArrayType($type); 622 return 0 if $object->GetSequenceType($type); 623 return 0 if $object->IsEnumType($type); 624 return 0 if $object->IsStringType($type); 625 return 0 if $object->IsTypedArrayType($type); 626 return 0 if $webCoreTypeHash{$type}; 627 return 0 if $type eq "any"; 628 629 return 1; 630} 631 632sub IsCallbackInterface 633{ 634 my $object = shift; 635 my $type = shift; 636 637 return 0 unless $object->IsWrapperType($type); 638 639 my $idlFile = $object->IDLFileForInterface($type) 640 or die("Could NOT find IDL file for interface \"$type\"!\n"); 641 642 open FILE, "<", $idlFile; 643 my @lines = <FILE>; 644 close FILE; 645 646 my $fileContents = join('', @lines); 647 return ($fileContents =~ /callback\s+interface\s+(\w+)/gs); 648} 649 650sub GenerateConditionalString 651{ 652 my $generator = shift; 653 my $node = shift; 654 655 my $conditional = $node->extendedAttributes->{"Conditional"}; 656 if ($conditional) { 657 return $generator->GenerateConditionalStringFromAttributeValue($conditional); 658 } else { 659 return ""; 660 } 661} 662 663sub GenerateConstructorConditionalString 664{ 665 my $generator = shift; 666 my $node = shift; 667 668 my $conditional = $node->extendedAttributes->{"ConstructorConditional"}; 669 if ($conditional) { 670 return $generator->GenerateConditionalStringFromAttributeValue($conditional); 671 } else { 672 return ""; 673 } 674} 675 676sub GenerateConditionalStringFromAttributeValue 677{ 678 my $generator = shift; 679 my $conditional = shift; 680 681 my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : '')); 682 if ($operator) { 683 # Avoid duplicated conditions. 684 my %conditions; 685 map { $conditions{$_} = 1 } split('\\' . $operator, $conditional); 686 return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")"; 687 } else { 688 return "ENABLE(" . $conditional . ")"; 689 } 690} 691 692sub GenerateCompileTimeCheckForEnumsIfNeeded 693{ 694 my ($generator, $interface) = @_; 695 my $interfaceName = $interface->name; 696 my @checks = (); 697 # If necessary, check that all constants are available as enums with the same value. 698 if (!$interface->extendedAttributes->{"DoNotCheckConstants"} && @{$interface->constants}) { 699 push(@checks, "\n"); 700 foreach my $constant (@{$interface->constants}) { 701 my $reflect = $constant->extendedAttributes->{"Reflect"}; 702 my $name = $reflect ? $reflect : $constant->name; 703 my $value = $constant->value; 704 my $conditional = $constant->extendedAttributes->{"Conditional"}; 705 706 if ($conditional) { 707 my $conditionalString = $generator->GenerateConditionalStringFromAttributeValue($conditional); 708 push(@checks, "#if ${conditionalString}\n"); 709 } 710 711 if ($constant->extendedAttributes->{"ImplementedBy"}) { 712 push(@checks, "COMPILE_ASSERT($value == " . $constant->extendedAttributes->{"ImplementedBy"} . "::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); 713 } else { 714 push(@checks, "COMPILE_ASSERT($value == ${interfaceName}::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n"); 715 } 716 717 if ($conditional) { 718 push(@checks, "#endif\n"); 719 } 720 } 721 push(@checks, "\n"); 722 } 723 return @checks; 724} 725 726sub ExtendedAttributeContains 727{ 728 my $object = shift; 729 my $callWith = shift; 730 return 0 unless $callWith; 731 my $keyword = shift; 732 733 my @callWithKeywords = split /\s*\&\s*/, $callWith; 734 return grep { $_ eq $keyword } @callWithKeywords; 735} 736 737# FIXME: This is backwards. We currently name the interface and the IDL files with the implementation name. We 738# should use the real interface name in the IDL files and then use ImplementedAs to map this to the implementation name. 739sub GetVisibleInterfaceName 740{ 741 my $object = shift; 742 my $interface = shift; 743 my $interfaceName = $interface->extendedAttributes->{"InterfaceName"}; 744 return $interfaceName ? $interfaceName : $interface->name; 745} 746 747sub InheritsInterface 748{ 749 my $object = shift; 750 my $interface = shift; 751 my $interfaceName = shift; 752 my $found = 0; 753 754 return 1 if $interfaceName eq $interface->name; 755 $object->ForAllParents($interface, sub { 756 my $currentInterface = shift; 757 if ($currentInterface->name eq $interfaceName) { 758 $found = 1; 759 } 760 return 1 if $found; 761 }, 0); 762 763 return $found; 764} 765 766sub InheritsExtendedAttribute 767{ 768 my $object = shift; 769 my $interface = shift; 770 my $extendedAttribute = shift; 771 my $found = 0; 772 773 return 1 if $interface->extendedAttributes->{$extendedAttribute}; 774 $object->ForAllParents($interface, sub { 775 my $currentInterface = shift; 776 if ($currentInterface->extendedAttributes->{$extendedAttribute}) { 777 $found = 1; 778 } 779 return 1 if $found; 780 }, 0); 781 782 return $found; 783} 784 7851; 786