d8941e1fc8d7e1e884ce22a7bdcef8c19c3973d6
[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
53 # Default constructor
54 sub new
55 {
56     my $object = shift;
57     my $reference = { };
58
59     $useDirectories = shift;
60     $useGenerator = shift;
61     $useOutputDir = shift;
62     $useLayerOnTop = shift;
63
64     bless($reference, $object);
65     return $reference;
66 }
67
68 sub StripModule($)
69 {
70     my $object = shift;
71     my $name = shift;
72     $name =~ s/[a-zA-Z0-9]*:://;
73     return $name;
74 }
75
76 sub ProcessDocument
77 {
78     my $object = shift;
79     $useDocument = shift;
80     my $defines = shift;
81   
82     my $ifaceName = "CodeGenerator" . $useGenerator;
83
84     # Dynamically load external code generation perl module
85     require $ifaceName . ".pm";
86     $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop);
87     unless (defined($codeGenerator)) {
88         my $classes = $useDocument->classes;
89         foreach my $class (@$classes) {
90             print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n";
91         }
92         return;
93     }
94
95     # Start the actual code generation!
96     $codeGenerator->GenerateModule($useDocument, $defines);
97
98     my $classes = $useDocument->classes;
99     foreach my $class (@$classes) {
100         print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n";
101         $codeGenerator->GenerateInterface($class, $defines);
102     }
103
104     $codeGenerator->finish();
105 }
106
107 sub AddMethodsConstantsAndAttributesFromParentClasses
108 {
109     # For the passed interface, recursively parse all parent
110     # IDLs in order to find out all inherited properties/methods.
111
112     my $object = shift;
113     my $dataNode = shift;
114
115     my @parents = @{$dataNode->parents};
116     my $parentsMax = @{$dataNode->parents};
117
118     my $constantsRef = $dataNode->constants;
119     my $functionsRef = $dataNode->functions;
120     my $attributesRef = $dataNode->attributes;
121
122     # Exception: For the DOM 'Node' is our topmost baseclass, not EventTargetNode.
123     return if $parentsMax eq 1 and $parents[0] eq "EventTargetNode";
124
125     my $ignoreParent = 1;
126     foreach (@{$dataNode->parents}) {
127         if ($ignoreParent) {
128             # Ignore first parent class, already handled by the generation itself.
129             $ignoreParent = 0;
130             next;
131         }
132
133         my $interface = $object->StripModule($_);
134
135         # Step #1: Find the IDL file associated with 'interface'
136         $endCondition = 0;
137         $foundFilename = "";
138
139         foreach (@{$useDirectories}) {
140             $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq "");
141         }
142
143         if ($foundFilename ne "") {
144             print "  |  |>  Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n";
145
146             # Step #2: Parse the found IDL file (in quiet mode).
147             my $parser = IDLParser->new(1);
148             my $document = $parser->Parse($foundFilename, "");
149
150             foreach my $class (@{$document->classes}) {
151                 # Step #3: Collect constants & functions & attributes of this parent-class
152                 my $constantsMax = @{$class->constants};
153                 my $functionsMax = @{$class->functions};
154                 my $attributesMax = @{$class->attributes};
155
156                 print "  |  |>  -> Inherting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n  |  |>\n";
157
158                 # Step #4: Concatenate data
159                 foreach (@{$class->constants}) {
160                     push(@$constantsRef, $_);
161                 }
162
163                 foreach (@{$class->functions}) {
164                     push(@$functionsRef, $_);
165                 }
166
167                 foreach (@{$class->attributes}) {
168                     push(@$attributesRef, $_);
169                 }
170
171                 # Step #4: Enter recursive parent search
172                 AddMethodsConstantsAndAttributesFromParentClasses($object, $class);
173             }
174         } else {
175             die("Could NOT find specified parent interface \"$interface\"!\n");
176         }
177     }
178 }
179
180 # Helper for all CodeGenerator***.pm modules
181 sub IsPrimitiveType
182 {
183     my $object = shift;
184     my $type = shift;
185
186     return 1 if ($primitiveTypeHash{$type});
187     return 0;
188 }
189
190 sub IsSVGAnimatedType
191 {
192     my $object = shift;
193     my $type = shift;
194
195     return 1 if ($svgAnimatedTypeHash{$type});
196     return 0; 
197 }
198
199 # Internal Helper
200 sub ScanDirectory
201 {
202     my $object = shift;
203
204     my $interface = shift;
205     my $directory = shift;
206     my $useDirectory = shift;
207     my $reportAllFiles = shift;
208
209     return if ($endCondition eq 1) and ($reportAllFiles eq 0);
210
211     chdir($directory) or die "[ERROR] Can't enter directory $directory: \"$!\"\n";
212     opendir(DIR, ".") or die "[ERROR] Can't open directory $directory: \"$!\"\n";
213
214     my @names = readdir(DIR) or die "[ERROR] Cant't read directory $directory: \"$!\"\n";
215     closedir(DIR);
216
217     foreach my $name (@names) {
218         # Skip if we already found the right file or
219         # if we encounter 'exotic' stuff (ie. '.', '..', '.svn')
220         next if ($endCondition eq 1) or ($name =~ /^\./);
221
222         # Recurisvely enter directory
223         if (-d $name) {
224             $object->ScanDirectory($interface, $name, $useDirectory, $reportAllFiles);
225             next;
226         }
227
228         # Check wheter we found the desired file
229         my $condition = ($name eq $interface);
230         $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/);
231
232         if ($condition) {
233             $foundFilename = "$directory/$name";
234
235             if ($reportAllFiles eq 0) {
236                 $endCondition = 1;
237             } else {
238                 push(@foundFilenames, $foundFilename);
239             }
240         }
241
242         chdir($useDirectory) or die "[ERROR] Can't change directory to $useDirectory: \"$!\"\n";
243     }
244 }
245
246 1;