2006-10-08 Nikolas Zimmermann <zimmermann@kde.org>
[WebKit-https.git] / WebCore / bindings / scripts / CodeGenerator.pm
1
2 # KDOM IDL parser
3 #
4 # Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
5 # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
6
7 # This file is part of the KDE project
8
9 # This library is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Library General Public
11 # License as published by the Free Software Foundation; either
12 # version 2 of the License, or (at your option) any later version.
13
14 # This library is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Library General Public License for more details.
18
19 # You should have received a copy of the GNU Library General Public License
20 # aint with this library; see the file COPYING.LIB.  If not, write to
21 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 # Boston, MA 02111-1307, USA.
23
24
25 package CodeGenerator;
26
27 my $useDocument = "";
28 my $useGenerator = "";
29 my $useOutputDir = "";
30 my $useDirectories = "";
31 my $useLayerOnTop = 0;
32
33 my $codeGenerator = 0;
34
35 my %primitiveTypeHash = ("int" => 1, "short" => 1, "long" => 1, 
36                          "unsigned int" => 1, "unsigned short" => 1,
37                          "unsigned long" => 1, "float" => 1,
38                          "double" => 1, "boolean" => 1, "void" => 1);
39
40 my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1,
41                            "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1,
42                            "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1,
43                            "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1,
44                            "SVGAnimatedPreserveAspectRatio" => 1,
45                            "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1,
46                            "SVGAnimatedTransformList" => 1);
47
48 # Helpers for 'ScanDirectory'
49 my $endCondition = 0;
50 my $foundFilename = "";
51 my @foundFilenames = ();
52 my $ignoreParent = 1;
53 my $defines = "";
54
55 # Default constructor
56 sub new
57 {
58     my $object = shift;
59     my $reference = { };
60
61     $useDirectories = shift;
62     $useGenerator = shift;
63     $useOutputDir = shift;
64     $useLayerOnTop = shift;
65
66     bless($reference, $object);
67     return $reference;
68 }
69
70 sub StripModule($)
71 {
72     my $object = shift;
73     my $name = shift;
74     $name =~ s/[a-zA-Z0-9]*:://;
75     return $name;
76 }
77
78 sub ProcessDocument
79 {
80     my $object = shift;
81     $useDocument = shift;
82     $defines = shift;
83
84     my $ifaceName = "CodeGenerator" . $useGenerator;
85
86     # Dynamically load external code generation perl module
87     require $ifaceName . ".pm";
88     $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop);
89     unless (defined($codeGenerator)) {
90         my $classes = $useDocument->classes;
91         foreach my $class (@$classes) {
92             print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n";
93         }
94         return;
95     }
96
97     # Start the actual code generation!
98     $codeGenerator->GenerateModule($useDocument, $defines);
99
100     my $classes = $useDocument->classes;
101     foreach my $class (@$classes) {
102         print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n";
103         $codeGenerator->GenerateInterface($class, $defines);
104     }
105
106     $codeGenerator->finish();
107 }
108
109 sub AddMethodsConstantsAndAttributesFromParentClasses
110 {
111     # For the passed interface, recursively parse all parent
112     # IDLs in order to find out all inherited properties/methods.
113
114     my $object = shift;
115     my $dataNode = shift;
116
117     my @parents = @{$dataNode->parents};
118     my $parentsMax = @{$dataNode->parents};
119
120     my $constantsRef = $dataNode->constants;
121     my $functionsRef = $dataNode->functions;
122     my $attributesRef = $dataNode->attributes;
123
124     # Exception: For the DOM 'Node' is our topmost baseclass, not EventTargetNode.
125     return if $parentsMax eq 1 and $parents[0] eq "EventTargetNode";
126
127     foreach (@{$dataNode->parents}) {
128         if ($ignoreParent) {
129             # Ignore first parent class, already handled by the generation itself.
130             $ignoreParent = 0;
131             next;
132         }
133
134         my $interface = $object->StripModule($_);
135
136         # Step #1: Find the IDL file associated with 'interface'
137         $endCondition = 0;
138         $foundFilename = "";
139
140         foreach (@{$useDirectories}) {
141             $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq "");
142         }
143
144         if ($foundFilename ne "") {
145             print "  |  |>  Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n";
146
147             # Step #2: Parse the found IDL file (in quiet mode).
148             my $parser = IDLParser->new(1);
149             my $document = $parser->Parse($foundFilename, $defines);
150
151             foreach my $class (@{$document->classes}) {
152                 # Step #3: Enter recursive parent search
153                 AddMethodsConstantsAndAttributesFromParentClasses($object, $class);
154
155                 # Step #4: Collect constants & functions & attributes of this parent-class
156                 my $constantsMax = @{$class->constants};
157                 my $functionsMax = @{$class->functions};
158                 my $attributesMax = @{$class->attributes};
159
160                 print "  |  |>  -> Inherting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n  |  |>\n";
161
162                 # Step #5: Concatenate data
163                 push(@$constantsRef, $_) foreach (@{$class->constants});
164                 push(@$functionsRef, $_) foreach (@{$class->functions});
165                 push(@$attributesRef, $_) foreach (@{$class->attributes});
166             }
167         } else {
168             die("Could NOT find specified parent interface \"$interface\"!\n");
169         }
170     }
171 }
172
173 # Helper for all CodeGenerator***.pm modules
174 sub IsPrimitiveType
175 {
176     my $object = shift;
177     my $type = shift;
178
179     return 1 if ($primitiveTypeHash{$type});
180     return 0;
181 }
182
183 sub IsSVGAnimatedType
184 {
185     my $object = shift;
186     my $type = shift;
187
188     return 1 if ($svgAnimatedTypeHash{$type});
189     return 0; 
190 }
191
192 # Internal Helper
193 sub ScanDirectory
194 {
195     my $object = shift;
196
197     my $interface = shift;
198     my $directory = shift;
199     my $useDirectory = shift;
200     my $reportAllFiles = shift;
201
202     return if ($endCondition eq 1) and ($reportAllFiles eq 0);
203
204     my $sourceRoot = $ENV{SOURCE_ROOT} || "";
205     $thisDir = "$sourceRoot/$directory";
206
207     opendir(DIR, $thisDir) or die "[ERROR] Can't open directory $thisDir: \"$!\"\n";
208
209     my @names = readdir(DIR) or die "[ERROR] Cant't read directory $thisDir \"$!\"\n";
210     closedir(DIR);
211
212     foreach my $name (@names) {
213         # Skip if we already found the right file or
214         # if we encounter 'exotic' stuff (ie. '.', '..', '.svn')
215         next if ($endCondition eq 1) or ($name =~ /^\./);
216
217         # Recurisvely enter directory
218         if (-d "$thisDir/$name") {
219             $object->ScanDirectory($interface, "$thisDir/$name", $useDirectory, $reportAllFiles);
220             next;
221         }
222
223         # Check wheter we found the desired file
224         my $condition = ($name eq $interface);
225         $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/);
226
227         if ($condition) {
228             $foundFilename = "$thisDir/$name";
229
230             if ($reportAllFiles eq 0) {
231                 $endCondition = 1;
232             } else {
233                 push(@foundFilenames, $foundFilename);
234             }
235         }
236     }
237 }
238
239 1;