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