4 # Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
5 # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
6 # Copyright (C) 2007 Apple Inc. All rights reserved.
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Library General Public License for more details.
18 # You should have received a copy of the GNU Library General Public License
19 # aint with this library; see the file COPYING.LIB. If not, write to
20 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 # Boston, MA 02110-1301, USA.
24 package CodeGenerator
;
27 my $useGenerator = "";
28 my $useOutputDir = "";
29 my $useDirectories = "";
30 my $useLayerOnTop = 0;
33 my $codeGenerator = 0;
37 my %primitiveTypeHash = ("int" => 1, "short" => 1, "long" => 1,
38 "unsigned int" => 1, "unsigned short" => 1,
39 "unsigned long" => 1, "float" => 1,
40 "double" => 1, "boolean" => 1, "void" => 1);
42 my %podTypeHash = ("RGBColor" => 1, "SVGLength" => 1, "SVGPoint" => 1, "SVGRect" => 1, "SVGNumber" => 1, "SVGMatrix" => 1, "SVGTransform" => 1);
44 my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1);
46 my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1, "SVGPaintType" => 1);
48 my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1,
49 "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1,
50 "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1,
51 "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1,
52 "SVGAnimatedPreserveAspectRatio" => 1,
53 "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1,
54 "SVGAnimatedTransformList" => 1);
56 # Helpers for 'ScanDirectory'
58 my $foundFilename = "";
59 my @foundFilenames = ();
69 $useDirectories = shift;
70 $useGenerator = shift;
71 $useOutputDir = shift;
72 $useLayerOnTop = shift;
73 $preprocessor = shift;
75 bless($reference, $object);
83 $name =~ s/[a-zA-Z0-9]*:://;
93 my $ifaceName = "CodeGenerator" . $useGenerator;
95 # Dynamically load external code generation perl module
96 require $ifaceName . ".pm";
97 $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop, $preprocessor);
98 unless (defined($codeGenerator)) {
99 my $classes = $useDocument->classes;
100 foreach my $class (@
$classes) {
101 print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n" if $verbose;
106 # Start the actual code generation!
107 $codeGenerator->GenerateModule($useDocument, $defines);
109 my $classes = $useDocument->classes;
110 foreach my $class (@
$classes) {
111 print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n" if $verbose;
112 $codeGenerator->GenerateInterface($class, $defines);
115 $codeGenerator->finish();
118 sub AddMethodsConstantsAndAttributesFromParentClasses
120 # For the passed interface, recursively parse all parent
121 # IDLs in order to find out all inherited properties/methods.
124 my $dataNode = shift;
126 my @parents = @
{$dataNode->parents};
127 my $parentsMax = @
{$dataNode->parents};
129 my $constantsRef = $dataNode->constants;
130 my $functionsRef = $dataNode->functions;
131 my $attributesRef = $dataNode->attributes;
133 # Exception: For the DOM 'Node' is our topmost baseclass, not EventTargetNode.
134 return if $parentsMax eq 1 and $parents[0] eq "EventTargetNode";
136 foreach (@
{$dataNode->parents}) {
138 # Ignore first parent class, already handled by the generation itself.
143 my $interface = $object->StripModule($_);
145 # Step #1: Find the IDL file associated with 'interface'
149 foreach (@
{$useDirectories}) {
150 $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq "");
153 if ($foundFilename ne "") {
154 print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose;
156 # Step #2: Parse the found IDL file (in quiet mode).
157 my $parser = IDLParser
->new(1);
158 my $document = $parser->Parse($foundFilename, $defines, $preprocessor);
160 foreach my $class (@
{$document->classes}) {
161 # Step #3: Enter recursive parent search
162 AddMethodsConstantsAndAttributesFromParentClasses
($object, $class);
164 # Step #4: Collect constants & functions & attributes of this parent-class
165 my $constantsMax = @
{$class->constants};
166 my $functionsMax = @
{$class->functions};
167 my $attributesMax = @
{$class->attributes};
169 print " | |> -> Inheriting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n | |>\n" if $verbose;
171 # Step #5: Concatenate data
172 push(@
$constantsRef, $_) foreach (@
{$class->constants});
173 push(@
$functionsRef, $_) foreach (@
{$class->functions});
174 push(@
$attributesRef, $_) foreach (@
{$class->attributes});
177 die("Could NOT find specified parent interface \"$interface\"!\n");
182 sub GetMethodsAndAttributesFromParentClasses
184 # For the passed interface, recursively parse all parent
185 # IDLs in order to find out all inherited properties/methods.
188 my $dataNode = shift;
190 my @parents = @
{$dataNode->parents};
192 return if @
{$dataNode->parents} == 0;
196 foreach (@
{$dataNode->parents}) {
197 my $interface = $object->StripModule($_);
198 if ($interface eq "EventTargetNode") {
202 # Step #1: Find the IDL file associated with 'interface'
206 foreach (@
{$useDirectories}) {
207 $object->ScanDirectory("${interface}.idl", $_, $_, 0) if $foundFilename eq "";
210 die("Could NOT find specified parent interface \"$interface\"!\n") if $foundFilename eq "";
212 print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose;
214 # Step #2: Parse the found IDL file (in quiet mode).
215 my $parser = IDLParser
->new(1);
216 my $document = $parser->Parse($foundFilename, $defines);
218 foreach my $class (@
{$document->classes}) {
219 # Step #3: Enter recursive parent search
220 push(@parentList, GetMethodsAndAttributesFromParentClasses
($object, $class));
222 # Step #4: Collect constants & functions & attributes of this parent-class
224 # print " | |> -> Inheriting $functionsMax functions amd $attributesMax attributes...\n | |>\n" if $verbose;
226 "name" => $class->name,
227 "functions" => $class->functions,
228 "attributes" => $class->attributes
231 # Step #5: Concatenate data
232 unshift(@parentList, $hash);
241 my ($object, $interfaceName) = @_;
243 # Step #1: Find the IDL file associated with 'interface'
247 foreach (@
{$useDirectories}) {
248 $object->ScanDirectory("${interfaceName}.idl", $_, $_, 0) if $foundFilename eq "";
250 die "Could NOT find specified parent interface \"$interfaceName\"!\n" if $foundFilename eq "";
252 print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interfaceName\"\n" if $verbose;
254 # Step #2: Parse the found IDL file (in quiet mode).
255 my $parser = IDLParser
->new(1);
256 my $document = $parser->Parse($foundFilename, $defines);
258 foreach my $interface (@
{$document->classes}) {
259 return $interface if $interface->name eq $interfaceName;
262 die "Interface definition not found";
265 # Helpers for all CodeGenerator***.pm modules
271 return 1 if $podTypeHash{$type};
280 return 1 if $primitiveTypeHash{$type};
289 return 1 if $stringTypeHash{$type};
298 return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type};
302 sub IsSVGAnimatedType
307 return 1 if $svgAnimatedTypeHash{$type};
316 my $interface = shift;
317 my $directory = shift;
318 my $useDirectory = shift;
319 my $reportAllFiles = shift;
321 return if ($endCondition eq 1) and ($reportAllFiles eq 0);
323 my $sourceRoot = $ENV{SOURCE_ROOT
};
324 my $thisDir = $sourceRoot ?
"$sourceRoot/$directory" : $directory;
326 if (!opendir(DIR
, $thisDir)) {
327 opendir(DIR
, $directory) or die "[ERROR] Can't open directory $thisDir or $directory: \"$!\"\n";
328 $thisDir = $directory;
331 my @names = readdir(DIR
) or die "[ERROR] Cant't read directory $thisDir \"$!\"\n";
334 foreach my $name (@names) {
335 # Skip if we already found the right file or
336 # if we encounter 'exotic' stuff (ie. '.', '..', '.svn')
337 next if ($endCondition eq 1) or ($name =~ /^\./);
339 # Recurisvely enter directory
340 if (-d
"$thisDir/$name") {
341 $object->ScanDirectory($interface, "$directory/$name", $useDirectory, $reportAllFiles);
345 # Check wheter we found the desired file
346 my $condition = ($name eq $interface);
347 $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/);
350 $foundFilename = "$thisDir/$name";
352 if ($reportAllFiles eq 0) {
355 push(@foundFilenames, $foundFilename);
361 # Uppercase the first letter while respecting WebKit style guidelines.
362 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
365 my ($object, $param) = @_;
366 my $ret = ucfirst($param);
367 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
371 # Lowercase the first letter while respecting WebKit style guidelines.
372 # URL becomes url, but SetURL becomes setURL.
375 my ($object, $param) = @_;
376 my $ret = lcfirst($param);
377 $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
378 $ret =~ s/jS/js/ if $ret =~ /^jS/;