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