blob: e2bbd3cf70845d0b4b890d1f996d7236e3ed35f2 [file] [log] [blame]
#
# KDOM IDL parser
#
# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
#
# This file is part of the KDE project
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# aint with this library; see the file COPYING.LIB. If not, write to
# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
#
package CodeGenerator;
my $useDocument = "";
my $useGenerator = "";
my $useOutputDir = "";
my $useDirectories = "";
my $useLayerOnTop = 0;
my $codeGenerator = 0;
my $verbose = 0;
my %primitiveTypeHash = ("int" => 1, "short" => 1, "long" => 1,
"unsigned int" => 1, "unsigned short" => 1,
"unsigned long" => 1, "float" => 1,
"double" => 1, "boolean" => 1, "void" => 1);
my %podTypeHash = ("RGBColor" => 1, "SVGLength" => 1, "SVGPoint" => 1, "SVGRect" => 1, "SVGNumber" => 1, "SVGMatrix" => 1, "SVGTransform" => 1);
my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1);
my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1, "SVGPaintType" => 1);
my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1,
"SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1,
"SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1,
"SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1,
"SVGAnimatedPreserveAspectRatio" => 1,
"SVGAnimatedRect" => 1, "SVGAnimatedString" => 1,
"SVGAnimatedTransformList" => 1);
# Helpers for 'ScanDirectory'
my $endCondition = 0;
my $foundFilename = "";
my @foundFilenames = ();
my $ignoreParent = 1;
my $defines = "";
# Default constructor
sub new
{
my $object = shift;
my $reference = { };
$useDirectories = shift;
$useGenerator = shift;
$useOutputDir = shift;
$useLayerOnTop = shift;
bless($reference, $object);
return $reference;
}
sub StripModule($)
{
my $object = shift;
my $name = shift;
$name =~ s/[a-zA-Z0-9]*:://;
return $name;
}
sub ProcessDocument
{
my $object = shift;
$useDocument = shift;
$defines = shift;
my $ifaceName = "CodeGenerator" . $useGenerator;
# Dynamically load external code generation perl module
require $ifaceName . ".pm";
$codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop);
unless (defined($codeGenerator)) {
my $classes = $useDocument->classes;
foreach my $class (@$classes) {
print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n" if $verbose;
}
return;
}
# Start the actual code generation!
$codeGenerator->GenerateModule($useDocument, $defines);
my $classes = $useDocument->classes;
foreach my $class (@$classes) {
print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n" if $verbose;
$codeGenerator->GenerateInterface($class, $defines);
}
$codeGenerator->finish();
}
sub AddMethodsConstantsAndAttributesFromParentClasses
{
# For the passed interface, recursively parse all parent
# IDLs in order to find out all inherited properties/methods.
my $object = shift;
my $dataNode = shift;
my @parents = @{$dataNode->parents};
my $parentsMax = @{$dataNode->parents};
my $constantsRef = $dataNode->constants;
my $functionsRef = $dataNode->functions;
my $attributesRef = $dataNode->attributes;
# Exception: For the DOM 'Node' is our topmost baseclass, not EventTargetNode.
return if $parentsMax eq 1 and $parents[0] eq "EventTargetNode";
foreach (@{$dataNode->parents}) {
if ($ignoreParent) {
# Ignore first parent class, already handled by the generation itself.
$ignoreParent = 0;
next;
}
my $interface = $object->StripModule($_);
# Step #1: Find the IDL file associated with 'interface'
$endCondition = 0;
$foundFilename = "";
foreach (@{$useDirectories}) {
$object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq "");
}
if ($foundFilename ne "") {
print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose;
# Step #2: Parse the found IDL file (in quiet mode).
my $parser = IDLParser->new(1);
my $document = $parser->Parse($foundFilename, $defines);
foreach my $class (@{$document->classes}) {
# Step #3: Enter recursive parent search
AddMethodsConstantsAndAttributesFromParentClasses($object, $class);
# Step #4: Collect constants & functions & attributes of this parent-class
my $constantsMax = @{$class->constants};
my $functionsMax = @{$class->functions};
my $attributesMax = @{$class->attributes};
print " | |> -> Inheriting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n | |>\n" if $verbose;
# Step #5: Concatenate data
push(@$constantsRef, $_) foreach (@{$class->constants});
push(@$functionsRef, $_) foreach (@{$class->functions});
push(@$attributesRef, $_) foreach (@{$class->attributes});
}
} else {
die("Could NOT find specified parent interface \"$interface\"!\n");
}
}
}
# Helpers for all CodeGenerator***.pm modules
sub IsPodType
{
my $object = shift;
my $type = shift;
return 1 if $podTypeHash{$type};
return 0;
}
sub IsPrimitiveType
{
my $object = shift;
my $type = shift;
return 1 if $primitiveTypeHash{$type};
return 0;
}
sub IsStringType
{
my $object = shift;
my $type = shift;
return 1 if $stringTypeHash{$type};
return 0;
}
sub IsNonPointerType
{
my $object = shift;
my $type = shift;
return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type};
return 0;
}
sub IsSVGAnimatedType
{
my $object = shift;
my $type = shift;
return 1 if $svgAnimatedTypeHash{$type};
return 0;
}
# Internal Helper
sub ScanDirectory
{
my $object = shift;
my $interface = shift;
my $directory = shift;
my $useDirectory = shift;
my $reportAllFiles = shift;
return if ($endCondition eq 1) and ($reportAllFiles eq 0);
my $sourceRoot = $ENV{SOURCE_ROOT} || "";
$thisDir = "$sourceRoot/$directory";
opendir(DIR, $thisDir) or die "[ERROR] Can't open directory $thisDir: \"$!\"\n";
my @names = readdir(DIR) or die "[ERROR] Cant't read directory $thisDir \"$!\"\n";
closedir(DIR);
foreach my $name (@names) {
# Skip if we already found the right file or
# if we encounter 'exotic' stuff (ie. '.', '..', '.svn')
next if ($endCondition eq 1) or ($name =~ /^\./);
# Recurisvely enter directory
if (-d "$thisDir/$name") {
$object->ScanDirectory($interface, "$directory/$name", $useDirectory, $reportAllFiles);
next;
}
# Check wheter we found the desired file
my $condition = ($name eq $interface);
$condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/);
if ($condition) {
$foundFilename = "$thisDir/$name";
if ($reportAllFiles eq 0) {
$endCondition = 1;
} else {
push(@foundFilenames, $foundFilename);
}
}
}
}
1;