# Copyright (c) 2010 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. package CodeGeneratorInspector; use strict; use Class::Struct; use File::stat; my %typeTransform; $typeTransform{"InspectorClient"} = { "forward" => "InspectorClient", "header" => "InspectorClient.h", }; $typeTransform{"PassRefPtr"} = { "forwardHeader" => "wtf/PassRefPtr.h", }; $typeTransform{"Object"} = { "param" => "PassRefPtr", "retVal" => "PassRefPtr", "forward" => "InspectorObject", "header" => "InspectorValues.h", "accessorSuffix" => "" }; $typeTransform{"Array"} = { "param" => "PassRefPtr", "retVal" => "PassRefPtr", "forward" => "InspectorArray", "header" => "InspectorValues.h", "accessorSuffix" => "" }; $typeTransform{"Value"} = { "param" => "PassRefPtr", "retVal" => "PassRefPtr", "forward" => "InspectorValue", "header" => "InspectorValues.h", "accessorSuffix" => "" }; $typeTransform{"String"} = { "param" => "const String&", "retVal" => "String", "forward" => "String", "header" => "PlatformString.h", "accessorSuffix" => "String" }; $typeTransform{"long"} = { "param" => "long", "retVal" => "long", "forward" => "", "header" => "", "accessorSuffix" => "Number" }; $typeTransform{"int"} = { "param" => "int", "retVal" => "int", "forward" => "", "header" => "", "accessorSuffix" => "Number", }; $typeTransform{"unsigned long"} = { "param" => "unsigned long", "retVal" => "unsigned long", "forward" => "", "header" => "", "accessorSuffix" => "Number" }; $typeTransform{"boolean"} = { "param" => "bool", "retVal"=> "bool", "forward" => "", "header" => "", "accessorSuffix" => "Bool" }; $typeTransform{"void"} = { "retVal" => "void", "forward" => "", "header" => "" }; # Default License Templates my $licenseTemplate = << "EOF"; // Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. EOF my $codeGenerator; my $outputDir; my $outputHeadersDir; my $writeDependencies; my $verbose; my $namespace; my $frontendClassName; my %frontendTypes; my %frontendMethods; my @frontendMethodsImpl; my $frontendConstructor; my $frontendFooter; my $callId = new domSignature(); # it is just structure for describing parameters from IDLStructure.pm. $callId->type("long"); $callId->name("callId"); # Default constructor sub new { my $object = shift; my $reference = { }; $codeGenerator = shift; $outputDir = shift; $outputHeadersDir = shift; shift; # $useLayerOnTop shift; # $preprocessor $writeDependencies = shift; $verbose = shift; bless($reference, $object); return $reference; } # Params: 'idlDocument' struct sub GenerateModule { my $object = shift; my $dataNode = shift; $namespace = $dataNode->module; $namespace =~ s/core/WebCore/; } # Params: 'idlDocument' struct sub GenerateInterface { my $object = shift; my $interface = shift; my $defines = shift; my $className = $interface->name; $frontendClassName = "Remote" . $className . "Frontend"; $frontendConstructor = " ${frontendClassName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }"; $frontendFooter = " InspectorClient* m_inspectorClient;"; $frontendTypes{"String"} = 1; $frontendTypes{"InspectorClient"} = 1; $frontendTypes{"PassRefPtr"} = 1; generateFunctions($interface); } sub generateFunctions { my $interface = shift; foreach my $function (@{$interface->functions}) { generateFrontendFunction($function); } } sub generateFrontendFunction { my $function = shift; my $functionName; my $notify = $function->signature->extendedAttributes->{"notify"}; if ($notify) { $functionName = $function->signature->name; } else { my $customResponse = $function->signature->extendedAttributes->{"customResponse"}; $functionName = $customResponse ? $customResponse : "did" . ucfirst($function->signature->name); } my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); # just keep only out parameters for frontend interface. unshift(@argsFiltered, $callId) if !$notify; # Add callId as the first argument for all frontend did* methods. map($frontendTypes{$_->type} = 1, @argsFiltered); # register required types. my $arguments = join(", ", map($typeTransform{$_->type}->{"param"} . " " . $_->name, @argsFiltered)); # prepare arguments for function signature. my @pushArguments = map(" arguments->push" . $typeTransform{$_->type}->{"accessorSuffix"} . "(" . $_->name . ");", @argsFiltered); my $signature = " void ${functionName}(${arguments});"; if (!$frontendMethods{${signature}}) { $frontendMethods{${signature}} = 1; my @function; push(@function, "void ${frontendClassName}::${functionName}(${arguments})"); push(@function, "{"); push(@function, " RefPtr arguments = InspectorArray::create();"); push(@function, " arguments->pushString(\"$functionName\");"); push(@function, @pushArguments); push(@function, " m_inspectorClient->sendMessageToFrontend(arguments->toJSONString());"); push(@function, "}"); push(@function, ""); push(@frontendMethodsImpl, @function); } } sub generateHeader { my $className = shift; my $types = shift; my $constructor = shift; my $methods = shift; my $footer = shift; my $forwardHeaders = join("\n", sort(map("#include <" . $typeTransform{$_}->{"forwardHeader"} . ">", grep($typeTransform{$_}->{"forwardHeader"}, keys %{$types})))); my $forwardDeclarations = join("\n", sort(map("class " . $typeTransform{$_}->{"forward"} . ";", grep($typeTransform{$_}->{"forward"}, keys %{$types})))); my $methodsDeclarations = join("\n", keys %{$methods}); my $headerBody = << "EOF"; // Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef ${className}_h #define ${className}_h ${forwardHeaders} namespace $namespace { $forwardDeclarations class $className { public: $constructor $methodsDeclarations private: $footer }; } // namespace $namespace #endif // !defined(${className}_h) EOF return $headerBody; } sub generateSource { my $className = shift; my $types = shift; my $methods = shift; my @sourceContent = split("\r", $licenseTemplate); push(@sourceContent, "\n#include \"config.h\""); push(@sourceContent, "#include \"$className.h\""); push(@sourceContent, ""); push(@sourceContent, "#if ENABLE(INSPECTOR)"); push(@sourceContent, ""); my %headers; foreach my $type (keys %{$types}) { $headers{"#include \"" . $typeTransform{$type}->{"header"} . "\""} = 1 if !$typeTransform{$type}->{"header"} eq ""; } push(@sourceContent, sort keys %headers); push(@sourceContent, ""); push(@sourceContent, "namespace $namespace {"); push(@sourceContent, ""); push(@sourceContent, @{$methods}); push(@sourceContent, ""); push(@sourceContent, "} // namespace $namespace"); push(@sourceContent, ""); push(@sourceContent, "#endif // ENABLE(INSPECTOR)"); push(@sourceContent, ""); return @sourceContent; } sub finish { my $object = shift; open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp"; print $SOURCE join("\n", generateSource($frontendClassName, \%frontendTypes, \@frontendMethodsImpl)); close($SOURCE); undef($SOURCE); open(my $HEADER, ">$outputHeadersDir/$frontendClassName.h") || die "Couldn't open file $outputHeadersDir/$frontendClassName.h"; print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \%frontendMethods, $frontendFooter); close($HEADER); undef($HEADER); } 1;