don't discard iframe children.
[kdelibs.git] / khtml / bindings / scripts / CodeGenerator.pm
blob85271137b7fcae837f67bb1879fa2c1bf6b7ea69
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 Apple Inc. All rights reserved.
7 #
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;
26 my $useDocument = "";
27 my $useGenerator = "";
28 my $useOutputDir = "";
29 my $useDirectories = "";
30 my $useLayerOnTop = 0;
31 my $preprocessor;
33 my $codeGenerator = 0;
35 my $verbose = 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'
57 my $endCondition = 0;
58 my $foundFilename = "";
59 my @foundFilenames = ();
60 my $ignoreParent = 1;
61 my $defines = "";
63 # Default constructor
64 sub new
66 my $object = shift;
67 my $reference = { };
69 $useDirectories = shift;
70 $useGenerator = shift;
71 $useOutputDir = shift;
72 $useLayerOnTop = shift;
73 $preprocessor = shift;
75 bless($reference, $object);
76 return $reference;
79 sub StripModule($)
81 my $object = shift;
82 my $name = shift;
83 $name =~ s/[a-zA-Z0-9]*:://;
84 return $name;
87 sub ProcessDocument
89 my $object = shift;
90 $useDocument = shift;
91 $defines = shift;
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;
103 return;
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.
123 my $object = shift;
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}) {
137 if ($ignoreParent) {
138 # Ignore first parent class, already handled by the generation itself.
139 $ignoreParent = 0;
140 next;
143 my $interface = $object->StripModule($_);
145 # Step #1: Find the IDL file associated with 'interface'
146 $endCondition = 0;
147 $foundFilename = "";
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});
176 } else {
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.
187 my $object = shift;
188 my $dataNode = shift;
190 my @parents = @{$dataNode->parents};
192 return if @{$dataNode->parents} == 0;
194 my @parentList = ();
196 foreach (@{$dataNode->parents}) {
197 my $interface = $object->StripModule($_);
198 if ($interface eq "EventTargetNode") {
199 $interface = "Node";
202 # Step #1: Find the IDL file associated with 'interface'
203 $endCondition = 0;
204 $foundFilename = "";
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;
225 my $hash = {
226 "name" => $class->name,
227 "functions" => $class->functions,
228 "attributes" => $class->attributes
231 # Step #5: Concatenate data
232 unshift(@parentList, $hash);
236 return @parentList;
239 sub ParseInterface
241 my ($object, $interfaceName) = @_;
243 # Step #1: Find the IDL file associated with 'interface'
244 $endCondition = 0;
245 $foundFilename = "";
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
266 sub IsPodType
268 my $object = shift;
269 my $type = shift;
271 return 1 if $podTypeHash{$type};
272 return 0;
275 sub IsPrimitiveType
277 my $object = shift;
278 my $type = shift;
280 return 1 if $primitiveTypeHash{$type};
281 return 0;
284 sub IsStringType
286 my $object = shift;
287 my $type = shift;
289 return 1 if $stringTypeHash{$type};
290 return 0;
293 sub IsNonPointerType
295 my $object = shift;
296 my $type = shift;
298 return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type};
299 return 0;
302 sub IsSVGAnimatedType
304 my $object = shift;
305 my $type = shift;
307 return 1 if $svgAnimatedTypeHash{$type};
308 return 0;
311 # Internal Helper
312 sub ScanDirectory
314 my $object = shift;
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";
332 closedir(DIR);
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);
342 next;
345 # Check wheter we found the desired file
346 my $condition = ($name eq $interface);
347 $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/);
349 if ($condition) {
350 $foundFilename = "$thisDir/$name";
352 if ($reportAllFiles eq 0) {
353 $endCondition = 1;
354 } else {
355 push(@foundFilenames, $foundFilename);
361 # Uppercase the first letter while respecting WebKit style guidelines.
362 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
363 sub WK_ucfirst
365 my ($object, $param) = @_;
366 my $ret = ucfirst($param);
367 $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
368 return $ret;
371 # Lowercase the first letter while respecting WebKit style guidelines.
372 # URL becomes url, but SetURL becomes setURL.
373 sub WK_lcfirst
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/;
379 return $ret;