don't discard iframe children.
[kdelibs.git] / khtml / bindings / scripts / IDLParser.pm
blobde7cf9cc30d1b81d8a42cdc1fa8a3cb7b0f55cb0
1 #
2 # KDOM IDL parser
4 # Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
5 #
6 # This file is part of the KDE project
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 IDLParser;
26 use IPC::Open2;
27 use IDLStructure;
29 use constant MODE_UNDEF => 0; # Default mode.
31 use constant MODE_MODULE => 10; # 'module' section
32 use constant MODE_INTERFACE => 11; # 'interface' section
33 use constant MODE_EXCEPTION => 12; # 'exception' section
34 use constant MODE_ALIAS => 13; # 'alias' section
36 # Helper variables
37 my @temporaryContent = "";
39 my $parseMode = MODE_UNDEF;
40 my $preservedParseMode = MODE_UNDEF;
42 my $beQuiet; # Should not display anything on STDOUT?
43 my $document = 0; # Will hold the resulting 'idlDocument'
45 # Default Constructor
46 sub new
48 my $object = shift;
49 my $reference = { };
51 $document = 0;
52 $beQuiet = shift;
54 bless($reference, $object);
55 return $reference;
58 # Returns the parsed 'idlDocument'
59 sub Parse
61 my $object = shift;
62 my $fileName = shift;
63 my $defines = shift;
64 my $preprocessor = shift;
66 if (!$preprocessor) {
67 $preprocessor = "/usr/bin/gcc -E -P -x c++";
70 if (!$defines) {
71 $defines = "";
74 print " | *** Starting to parse $fileName...\n |\n" unless $beQuiet;
76 open2(\*PP_OUT, \*PP_IN, split(' ', $preprocessor), (map { "-D$_" } split(' ', $defines)), $fileName);
77 close PP_IN;
78 my @documentContent = <PP_OUT>;
79 close PP_OUT;
81 my $dataAvailable = 0;
83 # Simple IDL Parser (tm)
84 foreach (@documentContent) {
85 my $newParseMode = $object->DetermineParseMode($_);
87 if ($newParseMode ne MODE_UNDEF) {
88 if ($dataAvailable eq 0) {
89 $dataAvailable = 1; # Start node building...
90 } else {
91 $object->ProcessSection();
95 # Update detected data stream mode...
96 if ($newParseMode ne MODE_UNDEF) {
97 $parseMode = $newParseMode;
100 push(@temporaryContent, $_);
103 # Check if there is anything remaining to parse...
104 if (($parseMode ne MODE_UNDEF) and ($#temporaryContent > 0)) {
105 $object->ProcessSection();
108 print " | *** Finished parsing!\n" unless $beQuiet;
110 $document->fileName($fileName);
112 return $document;
115 sub ParseModule
117 my $object = shift;
118 my $dataNode = shift;
120 print " |- Trying to parse module...\n" unless $beQuiet;
122 my $data = join("", @temporaryContent);
123 $data =~ /$IDLStructure::moduleSelector/;
125 my $moduleName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)"));
126 $dataNode->module($moduleName);
128 print " |----> Module; NAME \"$moduleName\"\n |-\n |\n" unless $beQuiet;
131 sub dumpExtendedAttributes
133 my $padStr = shift;
134 my $attrs = shift;
136 if (!%{$attrs}) {
137 return "";
140 my @temp;
141 while (($name, $value) = each(%{$attrs})) {
142 push(@temp, "$name=$value");
145 return $padStr . "[" . join(", ", @temp) . "]";
148 sub parseExtendedAttributes
150 my $str = shift;
151 $str =~ s/\[\s*(.*?)\s*\]/$1/g;
153 my %attrs = ();
155 foreach my $value (split(/\s*,\s*/, $str)) {
156 ($name,$value) = split(/\s*=\s*/, $value, 2);
158 # Attributes with no value are set to be true
159 $value = 1 unless defined $value;
160 $attrs{$name} = $value;
163 return \%attrs;
166 sub ParseInterface
168 my $object = shift;
169 my $dataNode = shift;
170 my $sectionName = shift;
172 my $data = join("", @temporaryContent);
174 # Look for end-of-interface mark
175 $data =~ /};/g;
176 $data = substr($data, index($data, $sectionName), pos($data) - length($data));
178 $data =~ s/[\n\r]/ /g;
180 # Beginning of the regexp parsing magic
181 if ($sectionName eq "exception") {
182 print " |- Trying to parse exception...\n" unless $beQuiet;
184 my $exceptionName = "";
185 my $exceptionData = "";
186 my $exceptionDataName = "";
187 my $exceptionDataType = "";
189 # Match identifier of the exception, and enclosed data...
190 $data =~ /$IDLStructure::exceptionSelector/;
191 $exceptionName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)"));
192 $exceptionData = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)"));
194 ('' =~ /^/); # Reset variables needed for regexp matching
196 # ... parse enclosed data (get. name & type)
197 $exceptionData =~ /$IDLStructure::exceptionSubSelector/;
198 $exceptionDataType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)"));
199 $exceptionDataName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)"));
201 # Fill in domClass datastructure
202 $dataNode->name($exceptionName);
204 my $newDataNode = new domAttribute();
205 $newDataNode->type("readonly attribute");
206 $newDataNode->signature(new domSignature());
208 $newDataNode->signature->name($exceptionDataName);
209 $newDataNode->signature->type($exceptionDataType);
211 my $arrayRef = $dataNode->attributes;
212 push(@$arrayRef, $newDataNode);
214 print " |----> Exception; NAME \"$exceptionName\" DATA TYPE \"$exceptionDataType\" DATA NAME \"$exceptionDataName\"\n |-\n |\n" unless $beQuiet;
215 } elsif ($sectionName eq "interface") {
216 print " |- Trying to parse interface...\n" unless $beQuiet;
218 my $interfaceName = "";
219 my $interfaceData = "";
221 # Match identifier of the interface, and enclosed data...
222 $data =~ /$IDLStructure::interfaceSelector/;
224 $interfaceExtendedAttributes = (defined($1) ? $1 : " "); chop($interfaceExtendedAttributes);
225 $interfaceName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)"));
226 $interfaceBase = (defined($3) ? $3 : "");
227 $interfaceData = (defined($4) ? $4 : die("Parsing error!\nSource:\n$data\n)"));
229 # Fill in known parts of the domClass datastructure now...
230 $dataNode->name($interfaceName);
231 $dataNode->extendedAttributes(parseExtendedAttributes($interfaceExtendedAttributes));
233 # Inheritance detection
234 my @interfaceParents = split(/,/, $interfaceBase);
235 foreach(@interfaceParents) {
236 my $line = $_;
237 $line =~ s/\s*//g;
239 my $arrayRef = $dataNode->parents;
240 push(@$arrayRef, $line);
243 $interfaceData =~ s/[\n\r]/ /g;
244 my @interfaceMethods = split(/;/, $interfaceData);
246 foreach my $line (@interfaceMethods) {
247 if ($line =~ /attribute/) {
248 $line =~ /$IDLStructure::interfaceAttributeSelector/;
250 my $attributeType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)"));
251 my $attributeExtendedAttributes = (defined($2) ? $2 : " "); chop($attributeExtendedAttributes);
253 my $attributeDataType = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
254 my $attributeDataName = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)"));
256 ('' =~ /^/); # Reset variables needed for regexp matching
258 $line =~ /$IDLStructure::getterRaisesSelector/;
259 my $getterException = (defined($1) ? $1 : "");
261 $line =~ /$IDLStructure::setterRaisesSelector/;
262 my $setterException = (defined($1) ? $1 : "");
264 my $newDataNode = new domAttribute();
265 $newDataNode->type($attributeType);
266 $newDataNode->signature(new domSignature());
268 $newDataNode->signature->name($attributeDataName);
269 $newDataNode->signature->type($attributeDataType);
270 $newDataNode->signature->extendedAttributes(parseExtendedAttributes($attributeExtendedAttributes));
272 my $arrayRef = $dataNode->attributes;
273 push(@$arrayRef, $newDataNode);
275 print " | |> Attribute; TYPE \"$attributeType\" DATA NAME \"$attributeDataName\" DATA TYPE \"$attributeDataType\" GET EXCEPTION? \"$getterException\" SET EXCEPTION? \"$setterException\"" .
276 dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet;
278 $getterException =~ s/\s+//g;
279 $setterException =~ s/\s+//g;
280 @{$newDataNode->getterExceptions} = split(/,/, $getterException);
281 @{$newDataNode->setterExceptions} = split(/,/, $setterException);
282 } elsif (($line !~ s/^\s*$//g) and ($line !~ /^\s*const/)) {
283 $line =~ /$IDLStructure::interfaceMethodSelector/ or die "Parsing error!\nSource:\n$line\n)";
285 my $methodExtendedAttributes = (defined($1) ? $1 : " "); chop($methodExtendedAttributes);
286 my $methodType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
287 my $methodName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
288 my $methodSignature = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)"));
290 ('' =~ /^/); # Reset variables needed for regexp matching
292 $line =~ /$IDLStructure::raisesSelector/;
293 my $methodException = (defined($1) ? $1 : "");
295 my $newDataNode = new domFunction();
297 $newDataNode->signature(new domSignature());
298 $newDataNode->signature->name($methodName);
299 $newDataNode->signature->type($methodType);
300 $newDataNode->signature->extendedAttributes(parseExtendedAttributes($methodExtendedAttributes));
302 print " | |- Method; TYPE \"$methodType\" NAME \"$methodName\" EXCEPTION? \"$methodException\"" .
303 dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet;
305 $methodException =~ s/\s+//g;
306 @{$newDataNode->raisesExceptions} = split(/,/, $methodException);
308 my @params = split(/,/, $methodSignature);
309 foreach(@params) {
310 my $line = $_;
312 $line =~ /$IDLStructure::interfaceParameterSelector/;
313 my $paramExtendedAttributes = (defined($1) ? $1 : " "); chop($paramExtendedAttributes);
314 my $paramType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
315 my $paramName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
317 my $paramDataNode = new domSignature();
318 $paramDataNode->name($paramName);
319 $paramDataNode->type($paramType);
320 $paramDataNode->extendedAttributes(parseExtendedAttributes($paramExtendedAttributes));
322 my $arrayRef = $newDataNode->parameters;
323 push(@$arrayRef, $paramDataNode);
325 print " | |> Param; TYPE \"$paramType\" NAME \"$paramName\"" .
326 dumpExtendedAttributes("\n | ", $paramDataNode->extendedAttributes) . "\n" unless $beQuiet;
329 my $arrayRef = $dataNode->functions;
330 push(@$arrayRef, $newDataNode);
331 } elsif ($line =~ /^\s*const/) {
332 $line =~ /$IDLStructure::constantSelector/;
333 my $constType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)"));
334 my $constName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
335 my $constValue = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)"));
337 my $newDataNode = new domConstant();
338 $newDataNode->name($constName);
339 $newDataNode->type($constType);
340 $newDataNode->value($constValue);
342 my $arrayRef = $dataNode->constants;
343 push(@$arrayRef, $newDataNode);
345 print " | |> Constant; TYPE \"$constType\" NAME \"$constName\" VALUE \"$constValue\"\n" unless $beQuiet;
349 print " |----> Interface; NAME \"$interfaceName\"" .
350 dumpExtendedAttributes("\n | ", $dataNode->extendedAttributes) . "\n |-\n |\n" unless $beQuiet;
354 # Internal helper
355 sub DetermineParseMode
357 my $object = shift;
358 my $line = shift;
360 my $mode = MODE_UNDEF;
361 if ($_ =~ /module/) {
362 $mode = MODE_MODULE;
363 } elsif ($_ =~ /interface/) {
364 $mode = MODE_INTERFACE;
365 } elsif ($_ =~ /exception/) {
366 $mode = MODE_EXCEPTION;
367 } elsif ($_ =~ /alias/) {
368 $mode = MODE_ALIAS;
371 return $mode;
374 # Internal helper
375 sub ProcessSection
377 my $object = shift;
379 if ($parseMode eq MODE_MODULE) {
380 die ("Two modules in one file! Fatal error!\n") if ($document ne 0);
381 $document = new idlDocument();
382 $object->ParseModule($document);
383 } elsif ($parseMode eq MODE_INTERFACE) {
384 my $node = new domClass();
385 $object->ParseInterface($node, "interface");
387 die ("No module specified! Fatal Error!\n") if ($document eq 0);
388 my $arrayRef = $document->classes;
389 push(@$arrayRef, $node);
390 } elsif($parseMode eq MODE_EXCEPTION) {
391 my $node = new domClass();
392 $object->ParseInterface($node, "exception");
394 die ("No module specified! Fatal Error!\n") if ($document eq 0);
395 my $arrayRef = $document->classes;
396 push(@$arrayRef, $node);
397 } elsif($parseMode eq MODE_ALIAS) {
398 print " |- Trying to parse alias...\n" unless $beQuiet;
400 my $line = join("", @temporaryContent);
401 $line =~ /$IDLStructure::aliasSelector/;
403 my $interfaceName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)"));
404 my $wrapperName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)"));
406 print " |----> Alias; INTERFACE \"$interfaceName\" WRAPPER \"$wrapperName\"\n |-\n |\n" unless $beQuiet;
408 # FIXME: Check if alias is already in aliases
409 my $aliases = $document->aliases;
410 $aliases->{$interfaceName} = $wrapperName;
413 @temporaryContent = "";