2010-07-12 Ilya Tikhonovsky <loislo@chromium.org>
[WebKit-https.git] / WebCore / inspector / CodeGeneratorInspector.pm
1 # Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 package CodeGeneratorInspector;
6
7 use strict;
8
9 use File::stat;
10
11 my %typeTransform;
12 $typeTransform{"InspectorClient"} = {
13     "forward" => "InspectorClient",
14     "header" => "InspectorClient.h",
15 };
16 $typeTransform{"PassRefPtr"} = {
17     "forwardHeader" => "wtf/PassRefPtr.h",
18 };
19 $typeTransform{"Object"} = {
20     "param" => "PassRefPtr<InspectorObject>",
21     "retVal" => "PassRefPtr<InspectorObject>",
22     "forward" => "InspectorObject",
23     "header" => "InspectorValues.h",
24     "push" => "push"
25 };
26 $typeTransform{"Array"} = {
27     "param" => "PassRefPtr<InspectorArray>",
28     "retVal" => "PassRefPtr<InspectorArray>",
29     "forward" => "InspectorArray",
30     "header" => "InspectorValues.h",
31     "push" => "push"
32 };
33 $typeTransform{"Value"} = {
34     "param" => "PassRefPtr<InspectorValue>",
35     "retVal" => "PassRefPtr<InspectorValue>",
36     "forward" => "InspectorValue",
37     "header" => "InspectorValues.h",
38     "push" => "push"
39 };
40 $typeTransform{"String"} = {
41     "param" => "const String&",
42     "retVal" => "String",
43     "forward" => "String",
44     "header" => "PlatformString.h",
45     "push" => "pushString"
46 };
47 $typeTransform{"long"} = {
48     "param" => "long",
49     "retVal" => "long",
50     "forward" => "",
51     "header" => "",
52     "push" => "pushNumber"
53 };
54 $typeTransform{"int"} = {
55     "param" => "int",
56     "retVal" => "int",
57     "forward" => "",
58     "header" => "",
59     "push" => "pushNumber"
60 };
61 $typeTransform{"unsigned long"} = {
62     "param" => "unsigned long",
63     "retVal" => "unsigned long",
64     "forward" => "",
65     "header" => "",
66     "push" => "pushNumber"
67 };
68 $typeTransform{"boolean"} = {
69     "param" => "bool",
70     "retVal"=> "bool",
71     "forward" => "",
72     "header" => "",
73     "push" => "pushBool"
74 };
75 $typeTransform{"void"} = {
76     "retVal" => "void",
77     "forward" => "",
78     "header" => ""
79 };
80
81 # Default License Templates
82
83 my $licenseTemplate = << "EOF";
84 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
85 // Use of this source code is governed by a BSD-style license that can be
86 // found in the LICENSE file.
87 EOF
88
89 my $codeGenerator;
90 my $outputDir;
91 my $writeDependencies;
92 my $verbose;
93
94 my $namespace;
95 my $frontendClassName;
96 my %discoveredTypes;
97 my %generatedFunctions;
98
99 my @frontendClassDeclaration;
100 my @functionDefinitions;
101
102 sub typeSpec
103 {
104     my $param = shift;
105     my $retValue = shift;
106
107     my $type = $typeTransform{$param->type}->{$retValue ? "retVal" : "param"};
108     $discoveredTypes{$param->type} = 1;
109     $type or die "invalid type specification \"" . $param->type ."\"";
110     return $type;
111 }
112
113 # Default constructor
114 sub new
115 {
116     my $object = shift;
117     my $reference = { };
118
119     $codeGenerator = shift;
120     $outputDir = shift;
121     shift; # $useLayerOnTop
122     shift; # $preprocessor
123     $writeDependencies = shift;
124     $verbose = shift;
125
126     bless($reference, $object);
127     return $reference;
128 }
129
130 # Params: 'idlDocument' struct
131 sub GenerateModule
132 {
133     my $object = shift;
134     my $dataNode = shift;
135
136     $namespace = $dataNode->module;
137     $namespace =~ s/core/WebCore/;
138 }
139
140 # Params: 'idlDocument' struct
141 sub GenerateInterface
142 {
143     my $object = shift;
144     my $interface = shift;
145     my $defines = shift;
146
147     my $className = $interface->name;
148     $frontendClassName = "Remote" . $className . "Frontend";
149
150     $discoveredTypes{"String"} = 1;
151     $discoveredTypes{"InspectorClient"} = 1;
152     $discoveredTypes{"PassRefPtr"} = 1;
153
154     push(@frontendClassDeclaration, "class $frontendClassName {");
155     push(@frontendClassDeclaration, "public:");
156     push(@frontendClassDeclaration, "    $frontendClassName(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }");
157     push(@frontendClassDeclaration, "");
158     push(@frontendClassDeclaration, generateFunctions($interface, $frontendClassName));
159     push(@frontendClassDeclaration, "");
160     push(@frontendClassDeclaration, "private:");
161     push(@frontendClassDeclaration, "    InspectorClient* m_inspectorClient;");
162     push(@frontendClassDeclaration, "};");
163 }
164
165 sub generateFunctions
166 {
167     my $interface = shift;
168     my $className = shift;
169
170     my @functionDeclarations;
171     foreach my $function (@{$interface->functions}) {
172         my $functionName;
173         my $argumentsDirectionFilter;
174         my $arguments;
175         my @functionBody;
176         push(@functionBody, "    RefPtr<InspectorArray> arguments = InspectorArray::create();");
177         if ($function->signature->extendedAttributes->{"notify"}) {
178             $functionName = $function->signature->name;
179             $argumentsDirectionFilter = "in";
180             $arguments = "";
181             push(@functionBody, "    arguments->pushString(\"$functionName\");");
182         } else {
183             my $customResponse = $function->signature->extendedAttributes->{"customResponse"};
184             $functionName = $customResponse ? $customResponse : "did" . ucfirst($function->signature->name);
185             $argumentsDirectionFilter = "out";
186             $arguments = "long callId";
187             push(@functionBody, "    arguments->pushString(\"$functionName\");");
188             push(@functionBody, "    arguments->pushNumber(callId);");
189         }
190
191         foreach my $parameter (@{$function->parameters}) {
192             if ($parameter->direction eq $argumentsDirectionFilter) {
193                 $parameter->name or die "empty argument name specified for function ${frontendClassName}::$functionName and argument type " . $parameter->type;
194                 $arguments = $arguments . ", " if ($arguments);
195                 $arguments = $arguments . typeSpec($parameter) . " " . $parameter->name;
196                 my $pushFunctionName =  $typeTransform{$parameter->type}->{"push"};
197                 push(@functionBody, "    arguments->$pushFunctionName(" . $parameter->name . ");");
198             }
199         }
200         push(@functionBody, "    m_inspectorClient->sendMessageToFrontend(arguments->toJSONString());");
201
202         my $signature = "    " . typeSpec($function->signature, 1) . " $functionName($arguments);";
203         if (!$generatedFunctions{${signature}}) {
204             $generatedFunctions{${signature}} = 1;
205             push(@functionDeclarations, $signature);
206
207             my @function;
208             push(@function, typeSpec($function->signature, 1) . " " . $className . "::" . $functionName . "(" . $arguments . ")");
209             push(@function, "{");
210             push(@function, @functionBody);
211             push(@function, "}");
212             push(@function, "");
213             push(@functionDefinitions, @function);
214         }
215     }
216     return @functionDeclarations;
217 }
218
219 sub generateHeader
220 {
221     my @headerContent = split("\r", $licenseTemplate);
222     push(@headerContent, "#ifndef ${frontendClassName}_h");
223     push(@headerContent, "#define ${frontendClassName}_h");
224     push(@headerContent, "");
225
226     my @forwardHeaders;
227     foreach my $type (keys %discoveredTypes) {
228         push(@forwardHeaders, "#include <" . $typeTransform{$type}->{"forwardHeader"} . ">") if !$typeTransform{$type}->{"forwardHeader"} eq  "";
229     }
230     push(@headerContent, sort @forwardHeaders);
231     push(@headerContent, "");
232     push(@headerContent, "namespace $namespace {");
233     push(@headerContent, "");
234
235     my @forwardDeclarations;
236     foreach my $type (keys %discoveredTypes) {
237         push(@forwardDeclarations, "class " . $typeTransform{$type}->{"forward"} . ";") if !$typeTransform{$type}->{"forward"} eq  "";
238     }
239     push(@headerContent, sort @forwardDeclarations);
240
241     push(@headerContent, "");
242     push(@headerContent, @frontendClassDeclaration);
243     push(@headerContent, "");
244     push(@headerContent, "} // namespace $namespace");
245     push(@headerContent, "");
246     push(@headerContent, "#endif // !defined(${frontendClassName}_h)");
247     push(@headerContent, "");
248     return @headerContent;
249 }
250
251 sub generateSource
252 {
253     my @sourceContent = split("\r", $licenseTemplate);
254     push(@sourceContent, "\n#include \"config.h\"");
255     push(@sourceContent, "#include \"$frontendClassName.h\"");
256     push(@sourceContent, "");
257     push(@sourceContent, "#if ENABLE(INSPECTOR)");
258     push(@sourceContent, "");
259
260     my %headers;
261     foreach my $type (keys %discoveredTypes) {
262         $headers{"#include \"" . $typeTransform{$type}->{"header"} . "\""} = 1 if !$typeTransform{$type}->{"header"} eq  "";
263     }
264     push(@sourceContent, sort keys %headers);
265     push(@sourceContent, "");
266     push(@sourceContent, "namespace $namespace {");
267     push(@sourceContent, "");
268     push(@sourceContent, @functionDefinitions);
269     push(@sourceContent, "");
270     push(@sourceContent, "} // namespace $namespace");
271     push(@sourceContent, "");
272     push(@sourceContent, "#endif // ENABLE(INSPECTOR)");
273     push(@sourceContent, "");
274     return @sourceContent;
275 }
276
277 sub finish
278 {
279     my $object = shift;
280
281     open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp";
282     open(my $HEADER, ">$outputDir/$frontendClassName.h") || die "Couldn't open file $outputDir/$frontendClassName.h";
283
284     print $SOURCE join("\n", generateSource());
285     close($SOURCE);
286     undef($SOURCE);
287
288     print $HEADER join("\n", generateHeader());
289     close($HEADER);
290     undef($HEADER);
291 }
292
293 1;