tizen beta release
[profile/ivi/webkit-efl.git] / Source / WebCore / bindings / scripts / CodeGenerator.pm
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 #
10 # This library is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU Library General Public
12 # License as published by the Free Software Foundation; either
13 # version 2 of the License, or (at your option) any later version.
14 #
15 # This library is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 # Library General Public License for more details.
19 #
20 # You should have received a copy of the GNU Library General Public License
21 # along with this library; see the file COPYING.LIB.  If not, write to
22 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 # Boston, MA 02110-1301, USA.
24 #
25
26 package CodeGenerator;
27
28 use strict;
29
30 use File::Find;
31
32 my $useDocument = "";
33 my $useGenerator = "";
34 my $useOutputDir = "";
35 my $useOutputHeadersDir = "";
36 my $useDirectories = "";
37 my $useLayerOnTop = 0;
38 my $preprocessor;
39 my $writeDependencies = 0;
40 my $defines = "";
41
42 my $codeGenerator = 0;
43
44 my $verbose = 0;
45
46 my %numericTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1,
47                        "unsigned int" => 1, "unsigned short" => 1,
48                        "unsigned long" => 1, "unsigned long long" => 1,
49                        "float" => 1, "double" => 1);
50
51 my %primitiveTypeHash = ( "boolean" => 1, "void" => 1, "Date" => 1);
52
53 my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1);
54
55 my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1);
56
57 my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1,
58                            "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1,
59                            "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1,
60                            "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1,
61                            "SVGAnimatedPreserveAspectRatio" => 1,
62                            "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1,
63                            "SVGAnimatedTransformList" => 1);
64
65 my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1,
66                                "onerror" => 1, "onload" => 1, "onmousedown" => 1,
67                                "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1,
68                                "onmouseup" => 1, "onresize" => 1, "onscroll" => 1,
69                                "onunload" => 1);
70
71 my %svgTypeNeedingTearOff = (
72     "SVGAngle" => "SVGPropertyTearOff<SVGAngle>",
73     "SVGLength" => "SVGPropertyTearOff<SVGLength>",
74     "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>",
75     "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>",
76     "SVGNumber" => "SVGPropertyTearOff<float>",
77     "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>",
78     "SVGPathSegList" => "SVGPathSegListPropertyTearOff",
79     "SVGPoint" => "SVGPropertyTearOff<FloatPoint>",
80     "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>",
81     "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>",
82     "SVGRect" => "SVGPropertyTearOff<FloatRect>",
83     "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>",
84     "SVGTransform" => "SVGPropertyTearOff<SVGTransform>",
85     "SVGTransformList" => "SVGTransformListPropertyTearOff"
86 );
87
88 my %svgTypeWithWritablePropertiesNeedingTearOff = (
89     "SVGPoint" => 1,
90     "SVGMatrix" => 1
91 );
92
93 # Cache of IDL file pathnames.
94 my $idlFiles;
95
96 # Default constructor
97 sub new
98 {
99     my $object = shift;
100     my $reference = { };
101
102     $useDirectories = shift;
103     $useGenerator = shift;
104     $useOutputDir = shift;
105     $useOutputHeadersDir = shift;
106     $useLayerOnTop = shift;
107     $preprocessor = shift;
108     $writeDependencies = shift;
109     $verbose = shift;
110
111     bless($reference, $object);
112     return $reference;
113 }
114
115 sub StripModule($)
116 {
117     my $object = shift;
118     my $name = shift;
119     $name =~ s/[a-zA-Z0-9]*:://;
120     return $name;
121 }
122
123 sub ProcessDocument
124 {
125     my $object = shift;
126     $useDocument = shift;
127     $defines = shift;
128
129     my $ifaceName = "CodeGenerator" . $useGenerator;
130     require $ifaceName . ".pm";
131
132     # Dynamically load external code generation perl module
133     $codeGenerator = $ifaceName->new($object, $useOutputDir, $useOutputHeadersDir, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose);
134     unless (defined($codeGenerator)) {
135         my $classes = $useDocument->classes;
136         foreach my $class (@$classes) {
137             print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n" if $verbose;
138         }
139         return;
140     }
141
142     # Start the actual code generation!
143     $codeGenerator->GenerateModule($useDocument, $defines);
144
145     my $classes = $useDocument->classes;
146     foreach my $class (@$classes) {
147         print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n" if $verbose;
148         $codeGenerator->GenerateInterface($class, $defines);
149     }
150
151     $codeGenerator->finish();
152 }
153
154 sub ForAllParents
155 {
156     my $object = shift;
157     my $dataNode = shift;
158     my $beforeRecursion = shift;
159     my $afterRecursion = shift;
160     my $parentsOnly = shift;
161
162     my $recurse;
163     $recurse = sub {
164         my $interface = shift;
165
166         for (@{$interface->parents}) {
167             my $interfaceName = $object->StripModule($_);
168             my $parentInterface = $object->ParseInterface($interfaceName, $parentsOnly);
169
170             if ($beforeRecursion) {
171                 &$beforeRecursion($parentInterface) eq 'prune' and next;
172             }
173             &$recurse($parentInterface);
174             &$afterRecursion($parentInterface) if $afterRecursion;
175         }
176     };
177
178     &$recurse($dataNode);
179 }
180
181 sub AddMethodsConstantsAndAttributesFromParentClasses
182 {
183     # Add to $dataNode all of its inherited interface members, except for those
184     # inherited through $dataNode's first listed parent.  If an array reference
185     # is passed in as $parents, the names of all ancestor interfaces visited
186     # will be appended to the array.  If $collectDirectParents is true, then
187     # even the names of $dataNode's first listed parent and its ancestors will
188     # be appended to $parents.
189
190     my $object = shift;
191     my $dataNode = shift;
192     my $parents = shift;
193     my $collectDirectParents = shift;
194
195     my $first = 1;
196
197     $object->ForAllParents($dataNode, sub {
198         my $interface = shift;
199
200         if ($first) {
201             # Ignore first parent class, already handled by the generation itself.
202             $first = 0;
203
204             if ($collectDirectParents) {
205                 # Just collect the names of the direct ancestor interfaces,
206                 # if necessary.
207                 push(@$parents, $interface->name);
208                 $object->ForAllParents($interface, sub {
209                     my $interface = shift;
210                     push(@$parents, $interface->name);
211                 }, undef, 1);
212             }
213
214             # Prune the recursion here.
215             return 'prune';
216         }
217
218         # Collect the name of this additional parent.
219         push(@$parents, $interface->name) if $parents;
220
221         print "  |  |>  -> Inheriting "
222             . @{$interface->constants} . " constants, "
223             . @{$interface->functions} . " functions, "
224             . @{$interface->attributes} . " attributes...\n  |  |>\n" if $verbose;
225
226         # Add this parent's members to $dataNode.
227         push(@{$dataNode->constants}, @{$interface->constants});
228         push(@{$dataNode->functions}, @{$interface->functions});
229         push(@{$dataNode->attributes}, @{$interface->attributes});
230     });
231 }
232
233 sub GetMethodsAndAttributesFromParentClasses
234 {
235     # For the passed interface, recursively parse all parent
236     # IDLs in order to find out all inherited properties/methods.
237
238     my $object = shift;
239     my $dataNode = shift;
240
241     my @parentList = ();
242
243     $object->ForAllParents($dataNode, undef, sub {
244         my $interface = shift;
245
246         my $hash = {
247             "name" => $interface->name,
248             "functions" => $interface->functions,
249             "attributes" => $interface->attributes
250         };
251
252         unshift(@parentList, $hash);
253     });
254
255     return @parentList;
256 }
257
258 sub IDLFileForInterface
259 {
260     my $object = shift;
261     my $interfaceName = shift;
262
263     unless ($idlFiles) {
264         my $sourceRoot = $ENV{SOURCE_ROOT};
265         my @directories = map { $_ = "$sourceRoot/$_" if $sourceRoot && -d "$sourceRoot/$_"; $_ } @$useDirectories;
266
267         $idlFiles = { };
268
269         my $wanted = sub {
270             $idlFiles->{$1} = $File::Find::name if /^([A-Z].*)\.idl$/;
271             $File::Find::prune = 1 if /^\../;
272         };
273         find($wanted, @directories);
274     }
275
276     return $idlFiles->{$interfaceName};
277 }
278
279 sub ParseInterface
280 {
281     my $object = shift;
282     my $interfaceName = shift;
283     my $parentsOnly = shift;
284
285     return undef if $interfaceName eq 'Object';
286
287     # Step #1: Find the IDL file associated with 'interface'
288     my $filename = $object->IDLFileForInterface($interfaceName)
289         or die("Could NOT find IDL file for interface \"$interfaceName\"!\n");
290
291     print "  |  |>  Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose;
292
293     # Step #2: Parse the found IDL file (in quiet mode).
294     my $parser = IDLParser->new(1);
295     my $document = $parser->Parse($filename, $defines, $preprocessor, $parentsOnly);
296
297     foreach my $interface (@{$document->classes}) {
298         return $interface if $interface->name eq $interfaceName;
299     }
300
301     die("Could NOT find interface definition for $interfaceName in $filename");
302 }
303
304 # Helpers for all CodeGenerator***.pm modules
305
306 sub AvoidInclusionOfType
307 {
308     my $object = shift;
309     my $type = shift;
310
311     # Special case: SVGPoint.h / SVGNumber.h do not exist.
312     return 1 if $type eq "SVGPoint" or $type eq "SVGNumber";
313     return 0;
314 }
315
316 sub IsNumericType
317 {
318     my $object = shift;
319     my $type = shift;
320
321     return 1 if $numericTypeHash{$type};
322     return 0;
323 }
324
325 sub IsPrimitiveType
326 {
327     my $object = shift;
328     my $type = shift;
329
330     return 1 if $primitiveTypeHash{$type};
331     return 1 if $numericTypeHash{$type};
332     return 0;
333 }
334
335 sub IsStringType
336 {
337     my $object = shift;
338     my $type = shift;
339
340     return 1 if $stringTypeHash{$type};
341     return 0;
342 }
343
344 sub 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
353 sub IsSVGTypeNeedingTearOff
354 {
355     my $object = shift;
356     my $type = shift;
357
358     return 1 if exists $svgTypeNeedingTearOff{$type};
359     return 0;
360 }
361
362 sub IsSVGTypeWithWritablePropertiesNeedingTearOff
363 {
364     my $object = shift;
365     my $type = shift;
366
367     return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type};
368     return 0;
369 }
370
371 sub GetSVGTypeNeedingTearOff
372 {
373     my $object = shift;
374     my $type = shift;
375
376     return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type};
377     return undef;
378 }
379
380 sub GetSVGWrappedTypeNeedingTearOff
381 {
382     my $object = shift;
383     my $type = shift;
384
385     my $svgTypeNeedingTearOff = $object->GetSVGTypeNeedingTearOff($type);
386     return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff;
387
388     if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) {
389         $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//;
390     } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) {
391         $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//;
392     } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) {
393         $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//;
394     }  elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) {
395         $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//;
396     } 
397
398     $svgTypeNeedingTearOff =~ s/>//;
399     return $svgTypeNeedingTearOff;
400 }
401
402 sub IsSVGAnimatedType
403 {
404     my $object = shift;
405     my $type = shift;
406
407     return 1 if $svgAnimatedTypeHash{$type};
408     return 0;
409 }
410
411 # Uppercase the first letter while respecting WebKit style guidelines.
412 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
413 sub WK_ucfirst
414 {
415     my ($object, $param) = @_;
416     my $ret = ucfirst($param);
417     $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
418
419     return $ret;
420 }
421
422 # Lowercase the first letter while respecting WebKit style guidelines.
423 # URL becomes url, but SetURL becomes setURL.
424 sub WK_lcfirst
425 {
426     my ($object, $param) = @_;
427     my $ret = lcfirst($param);
428     $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
429     $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
430     $ret =~ s/jS/js/ if $ret =~ /^jS/;
431     $ret =~ s/xML/xml/ if $ret =~ /^xML/;
432     $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
433
434     # For HTML5 FileSystem API Flags attributes.
435     # (create is widely used to instantiate an object and must be avoided.)
436     $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
437     $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
438
439     return $ret;
440 }
441
442 # Return the C++ namespace that a given attribute name string is defined in.
443 sub NamespaceForAttributeName
444 {
445     my ($object, $interfaceName, $attributeName) = @_;
446     return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName};
447     return "HTMLNames";
448 }
449
450 # Identifies overloaded functions and for each function adds an array with
451 # links to its respective overloads (including itself).
452 sub LinkOverloadedFunctions
453 {
454     my ($object, $dataNode) = @_;
455
456     my %nameToFunctionsMap = ();
457     foreach my $function (@{$dataNode->functions}) {
458         my $name = $function->signature->name;
459         $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name};
460         push(@{$nameToFunctionsMap{$name}}, $function);
461         $function->{overloads} = $nameToFunctionsMap{$name};
462         $function->{overloadIndex} = @{$nameToFunctionsMap{$name}};
463     }
464 }
465
466 sub AttributeNameForGetterAndSetter
467 {
468     my ($generator, $attribute) = @_;
469
470     my $attributeName = $attribute->signature->name;
471     my $attributeType = $generator->StripModule($attribute->signature->type);
472
473     # Avoid clash with C++ keyword.
474     $attributeName = "_operator" if $attributeName eq "operator";
475
476     # SVGAElement defines a non-virtual "String& target() const" method which clashes with "virtual String target() const" in Element.
477     # To solve this issue the SVGAElement method was renamed to "svgTarget", take care of that when calling this method.
478     $attributeName = "svgTarget" if $attributeName eq "target" and $attributeType eq "SVGAnimatedString";
479
480     # SVG animated types need to use a special attribute name.
481     # The rest of the special casing for SVG animated types is handled in the language-specific code generators.
482     $attributeName .= "Animated" if $generator->IsSVGAnimatedType($attributeType);
483
484     return $attributeName;
485 }
486
487 sub ContentAttributeName
488 {
489     my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
490
491     my $contentAttributeName = $attribute->signature->extendedAttributes->{"Reflect"};
492     return undef if !$contentAttributeName;
493
494     $contentAttributeName = lc $generator->AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "1";
495
496     my $namespace = $generator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
497
498     $implIncludes->{"${namespace}.h"} = 1;
499     return "WebCore::${namespace}::${contentAttributeName}Attr";
500 }
501
502 sub GetterExpressionPrefix
503 {
504     my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
505
506     my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute);
507
508     if (!$contentAttributeName) {
509         return $generator->WK_lcfirst($generator->AttributeNameForGetterAndSetter($attribute)) . "(";
510     }
511
512     my $functionName;
513     if ($attribute->signature->extendedAttributes->{"URL"}) {
514         if ($attribute->signature->extendedAttributes->{"NonEmpty"}) {
515             $functionName = "getNonEmptyURLAttribute";
516         } else {
517             $functionName = "getURLAttribute";
518         }
519     } elsif ($attribute->signature->type eq "boolean") {
520         $functionName = "hasAttribute";
521     } elsif ($attribute->signature->type eq "long") {
522         $functionName = "getIntegralAttribute";
523     } elsif ($attribute->signature->type eq "unsigned long") {
524         $functionName = "getUnsignedIntegralAttribute";
525     } else {
526         $functionName = "getAttribute";
527     }
528
529     return "$functionName($contentAttributeName"
530 }
531
532 sub SetterExpressionPrefix
533 {
534     my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
535
536     my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute);
537
538     if (!$contentAttributeName) {
539         return "set" . $generator->WK_ucfirst($generator->AttributeNameForGetterAndSetter($attribute)) . "(";
540     }
541
542     my $functionName;
543     if ($attribute->signature->type eq "boolean") {
544         $functionName = "setBooleanAttribute";
545     } elsif ($attribute->signature->type eq "long") {
546         $functionName = "setIntegralAttribute";
547     } elsif ($attribute->signature->type eq "unsigned long") {
548         $functionName = "setUnsignedIntegralAttribute";
549     } else {
550         $functionName = "setAttribute";
551     }
552
553     return "$functionName($contentAttributeName, "
554 }
555
556 sub ShouldCheckEnums
557 {
558     my $dataNode = shift;
559     return not $dataNode->extendedAttributes->{"DontCheckEnums"};
560 }
561
562 sub GenerateConditionalStringFromAttributeValue
563 {
564     my $generator = shift;
565     my $conditional = shift;
566
567     my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : ''));
568     if ($operator) {
569         # Avoid duplicated conditions.
570         my %conditions;
571         map { $conditions{$_} = 1 } split('\\' . $operator, $conditional);
572         return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")";
573     } else {
574         return "ENABLE(" . $conditional . ")";
575     }
576 }
577
578 sub GenerateCompileTimeCheckForEnumsIfNeeded
579 {
580     my ($generator, $dataNode) = @_;
581     my $interfaceName = $dataNode->name;
582     my @checks = ();
583     # If necessary, check that all constants are available as enums with the same value.
584     if (ShouldCheckEnums($dataNode) && @{$dataNode->constants}) {
585         push(@checks, "\n");
586         foreach my $constant (@{$dataNode->constants}) {
587             my $reflect = $constant->extendedAttributes->{"Reflect"};
588             my $name = $reflect ? $reflect : $constant->name;
589             my $value = $constant->value;
590             my $conditional = $constant->extendedAttributes->{"Conditional"};
591
592             if ($conditional) {
593                 my $conditionalString = $generator->GenerateConditionalStringFromAttributeValue($conditional);
594                 push(@checks, "#if ${conditionalString}\n");
595             }
596
597             push(@checks, "COMPILE_ASSERT($value == ${interfaceName}::$name, ${interfaceName}Enum${name}IsWrongUseDontCheckEnums);\n");
598
599             if ($conditional) {
600                 push(@checks, "#endif\n");
601             }
602         }
603         push(@checks, "\n");
604     }
605     return @checks;
606 }
607
608 1;