2010-11-18 Sheriff Bot <webkit.review.bot@gmail.com>
[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 Class::Struct;
10 use File::stat;
11
12 my %typeTransform;
13 $typeTransform{"InspectorClient"} = {
14     "forward" => "InspectorClient",
15     "header" => "InspectorClient.h",
16 };
17 $typeTransform{"Backend"} = {
18     "forward" => "InspectorBackend",
19     "header" => "InspectorBackend.h",
20     "domainAccessor" => "m_inspectorController->inspectorBackend()",
21 };
22 $typeTransform{"Controller"} = {
23     "forwardHeader" => "InspectorController.h",
24     "domainAccessor" => "m_inspectorController",
25 };
26 $typeTransform{"Debug"} = {
27     "forward" => "InspectorDebuggerAgent",
28     "header" => "InspectorDebuggerAgent.h",
29     "domainAccessor" => "m_inspectorController->debuggerAgent()",
30 };
31 $typeTransform{"Resource"} = {
32     "forward" => "InspectorResourceAgent",
33     "header" => "InspectorResourceAgent.h",
34     "domainAccessor" => "m_inspectorController->m_resourceAgent",
35 };
36 $typeTransform{"DOM"} = {
37     "forward" => "InspectorDOMAgent",
38     "header" => "InspectorDOMAgent.h",
39     "domainAccessor" => "m_inspectorController->domAgent()",
40 };
41 $typeTransform{"CSS"} = {
42     "forward" => "InspectorCSSAgent",
43     "header" => "InspectorCSSAgent.h",
44     "domainAccessor" => "m_inspectorController->cssAgent()",
45 };
46 $typeTransform{"ApplicationCache"} = {
47     "forward" => "InspectorApplicationCacheAgent",
48     "header" => "InspectorApplicationCacheAgent.h",
49     "domainAccessor" => "m_inspectorController->applicationCacheAgent()",
50 };
51 $typeTransform{"FileSystem"} = {
52     "forward" => "InspectorFileSystemAgent",
53     "header" => "InspectorFileSystemAgent.h",
54     "domainAccessor" => "m_inspectorController->fileSystemAgent()",
55 };
56 $typeTransform{"Profiler"} = {
57     "forward" => "InspectorProfilerAgent",
58     "header" => "InspectorProfilerAgent.h",
59     "domainAccessor" => "m_inspectorController->profilerAgent()",
60 };
61 $typeTransform{"Frontend"} = {
62     "forward" => "InspectorFrontend",
63     "header" => "InspectorFrontend.h",
64 };
65 $typeTransform{"PassRefPtr"} = {
66     "forwardHeader" => "wtf/PassRefPtr.h",
67 };
68 $typeTransform{"Object"} = {
69     "param" => "PassRefPtr<InspectorObject>",
70     "variable" => "RefPtr<InspectorObject>",
71     "defaultValue" => "InspectorObject::create()",
72     "forward" => "InspectorObject",
73     "header" => "InspectorValues.h",
74     "JSONType" => "Object"
75 };
76 $typeTransform{"Array"} = {
77     "param" => "PassRefPtr<InspectorArray>",
78     "variable" => "RefPtr<InspectorArray>",
79     "defaultValue" => "InspectorArray::create()",
80     "forward" => "InspectorArray",
81     "header" => "InspectorValues.h",
82     "JSONType" => "Array"
83 };
84 $typeTransform{"Value"} = {
85     "param" => "PassRefPtr<InspectorValue>",
86     "variable" => "RefPtr<InspectorValue>",
87     "defaultValue" => "InspectorValue::null()",
88     "forward" => "InspectorValue",
89     "header" => "InspectorValues.h",
90     "JSONType" => "Value"
91 };
92 $typeTransform{"String"} = {
93     "param" => "const String&",
94     "variable" => "String",
95     "defaultValue" => "\"\"",
96     "forwardHeader" => "wtf/Forward.h",
97     "header" => "PlatformString.h",
98     "JSONType" => "String"
99 };
100 $typeTransform{"long"} = {
101     "param" => "long",
102     "variable" => "long",
103     "defaultValue" => "0",
104     "forward" => "",
105     "header" => "",
106     "JSONType" => "Number"
107 };
108 $typeTransform{"int"} = {
109     "param" => "int",
110     "variable" => "int",
111     "defaultValue" => "0",
112     "forward" => "",
113     "header" => "",
114     "JSONType" => "Number",
115 };
116 $typeTransform{"unsigned long"} = {
117     "param" => "unsigned long",
118     "variable" => "unsigned long",
119     "defaultValue" => "0u",
120     "forward" => "",
121     "header" => "",
122     "JSONType" => "Number"
123 };
124 $typeTransform{"unsigned int"} = {
125     "param" => "unsigned int",
126     "variable" => "unsigned int",
127     "defaultValue" => "0u",
128     "forward" => "",
129     "header" => "",
130     "JSONType" => "Number"
131 };
132 $typeTransform{"double"} = {
133     "param" => "double",
134     "variable" => "double",
135     "defaultValue" => "0.0",
136     "forward" => "",
137     "header" => "",
138     "JSONType" => "Number"
139 };
140 $typeTransform{"boolean"} = {
141     "param" => "bool",
142     "variable"=> "bool",
143     "defaultValue" => "false",
144     "forward" => "",
145     "header" => "",
146     "JSONType" => "Boolean"
147 };
148 $typeTransform{"void"} = {
149     "forward" => "",
150     "header" => ""
151 };
152
153 # Default License Templates
154
155 my $licenseTemplate = << "EOF";
156 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
157 // Use of this source code is governed by a BSD-style license that can be
158 // found in the LICENSE file.
159 EOF
160
161 my $codeGenerator;
162 my $outputDir;
163 my $outputHeadersDir;
164 my $writeDependencies;
165 my $verbose;
166
167 my $namespace;
168
169 my $backendClassName;
170 my $backendJSStubName;
171 my %backendTypes;
172 my %backendMethods;
173 my @backendMethodsImpl;
174 my $backendConstructor;
175 my @backendConstantDeclarations;
176 my @backendConstantDefinitions;
177 my $backendFooter;
178 my @backendStubJS;
179
180 my $frontendClassName;
181 my %frontendTypes;
182 my %frontendMethods;
183 my @frontendMethodsImpl;
184 my $frontendConstructor;
185 my @frontendConstantDeclarations;
186 my @frontendConstantDefinitions;
187 my $frontendFooter;
188
189 # Default constructor
190 sub new
191 {
192     my $object = shift;
193     my $reference = { };
194
195     $codeGenerator = shift;
196     $outputDir = shift;
197     $outputHeadersDir = shift;
198     shift; # $useLayerOnTop
199     shift; # $preprocessor
200     $writeDependencies = shift;
201     $verbose = shift;
202
203     bless($reference, $object);
204     return $reference;
205 }
206
207 # Params: 'idlDocument' struct
208 sub GenerateModule
209 {
210     my $object = shift;
211     my $dataNode = shift;
212
213     $namespace = $dataNode->module;
214     $namespace =~ s/core/WebCore/;
215 }
216
217 # Params: 'idlDocument' struct
218 sub GenerateInterface
219 {
220     my $object = shift;
221     my $interface = shift;
222     my $defines = shift;
223
224     my $className = $interface->name;
225
226     $frontendClassName = $className . "Frontend";
227     $frontendConstructor = "    ${frontendClassName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }";
228     $frontendFooter = "    InspectorClient* m_inspectorClient;";
229     $frontendTypes{"String"} = 1;
230     $frontendTypes{"InspectorClient"} = 1;
231     $frontendTypes{"PassRefPtr"} = 1;
232
233     $backendClassName = $className . "BackendDispatcher";
234     $backendJSStubName = $className . "BackendStub";
235     my @backendHead;
236     push(@backendHead, "    ${backendClassName}(InspectorController* inspectorController) : m_inspectorController(inspectorController) { }");
237     push(@backendHead, "    void reportProtocolError(const long callId, const String& errorText) const;");
238     push(@backendHead, "    void dispatch(const String& message);");
239     push(@backendHead, "    static bool getCommandName(const String& message, String* result);");
240     $backendConstructor = join("\n", @backendHead);
241     $backendFooter = "    InspectorController* m_inspectorController;";
242     $backendTypes{"Controller"} = 1;
243     $backendTypes{"InspectorClient"} = 1;
244     $backendTypes{"PassRefPtr"} = 1;
245     $backendTypes{"Object"} = 1;
246
247     push(@backendMethodsImpl, generateBackendMessageParser());
248     generateFunctions($interface);
249
250     # Make dispatcher methods private on the backend.
251     push(@backendConstantDeclarations, "");
252     push(@backendConstantDeclarations, "private:");
253 }
254
255 sub generateFunctions
256 {
257     my $interface = shift;
258
259     foreach my $function (@{$interface->functions}) {
260         if ($function->signature->extendedAttributes->{"notify"}) {
261             generateFrontendFunction($function);
262         } else {
263             generateBackendFunction($function);
264         }
265     }
266     push(@backendMethodsImpl, generateBackendDispatcher());
267     push(@backendMethodsImpl, generateBackendReportProtocolError());
268
269     @backendStubJS = generateBackendStubJS($interface);
270 }
271
272 sub generateFrontendFunction
273 {
274     my $function = shift;
275
276     my $functionName = $function->signature->name;
277
278     my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); # just keep only out parameters for frontend interface.
279     map($frontendTypes{$_->type} = 1, @argsFiltered); # register required types.
280     my $arguments = join(", ", map($typeTransform{$_->type}->{"param"} . " " . $_->name, @argsFiltered)); # prepare arguments for function signature.
281
282     my $signature = "    void ${functionName}(${arguments});";
283     if (!$frontendMethods{${signature}}) {
284         $frontendMethods{${signature}} = 1;
285
286         my @function;
287         push(@function, "void ${frontendClassName}::${functionName}(${arguments})");
288         push(@function, "{");
289         push(@function, "    RefPtr<InspectorObject> ${functionName}Message = InspectorObject::create();");
290         push(@function, "    ${functionName}Message->setString(\"type\", \"event\");");
291         push(@function, "    ${functionName}Message->setString(\"event\", \"$functionName\");");
292         push(@function, "    RefPtr<InspectorObject> payloadDataObject = InspectorObject::create();");
293         my @pushArguments = map("    payloadDataObject->set" . $typeTransform{$_->type}->{"JSONType"} . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered);
294         push(@function, @pushArguments);
295         push(@function, "    ${functionName}Message->setObject(\"data\", payloadDataObject);");
296         push(@function, "    m_inspectorClient->sendMessageToFrontend(${functionName}Message->toJSONString());");
297
298         push(@function, "}");
299         push(@function, "");
300         push(@frontendMethodsImpl, @function);
301     }
302 }
303
304 sub generateBackendFunction
305 {
306     my $function = shift;
307
308     my $functionName = $function->signature->name;
309
310     push(@backendConstantDeclarations, "    static const char* ${functionName}Cmd;");
311     push(@backendConstantDefinitions, "const char* ${backendClassName}::${functionName}Cmd = \"${functionName}\";");
312
313     map($backendTypes{$_->type} = 1, @{$function->parameters}); # register required types
314     my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters});
315     my @outArgs = grep($_->direction eq "out", @{$function->parameters});
316
317     my $signature = "    void ${functionName}(long callId, InspectorObject* requestMessageObject);";
318     !$backendMethods{${signature}} || die "Duplicate function was detected for signature '$signature'.";
319     $backendMethods{${signature}} = $functionName;
320
321     my @function;
322     my $requestMessageObject = scalar(@inArgs) ? " requestMessageObject" : "";
323     push(@function, "void ${backendClassName}::${functionName}(long callId, InspectorObject*$requestMessageObject)");
324     push(@function, "{");
325     push(@function, "    RefPtr<InspectorArray> protocolErrors = InspectorArray::create();");
326     push(@function, "");
327
328     my $domain = $function->signature->extendedAttributes->{"handler"} || "Controller";
329     my $domainAccessor = $typeTransform{$domain}->{"domainAccessor"};
330     $backendTypes{$domain} = 1;
331     push(@function, "    if (!$domainAccessor)");
332     push(@function, "        protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");");
333     push(@function, "");
334
335     if (scalar(@inArgs)) {
336         # declare variables for all 'in' args;
337         push(@function, map("    " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @inArgs));
338
339         push(@function, "");
340         push(@function, "    RefPtr<InspectorObject> argumentsContainer;");
341         push(@function, "    if (!(argumentsContainer = requestMessageObject->getObject(\"arguments\"))) {");
342         push(@function, "        protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");");
343         push(@function, "    } else {");
344         push(@function, "        InspectorObject::const_iterator argumentsEndIterator = argumentsContainer->end();");
345
346         foreach my $parameter (@inArgs) {
347             my $name = $parameter->name;
348             my $type = $parameter->type;
349             my $variableType = $typeTransform{$type}->{"variable"};
350             my $JSONType = $typeTransform{$type}->{"JSONType"};
351
352             push(@function, "");
353             push(@function, "        InspectorObject::const_iterator ${name}ValueIterator = argumentsContainer->find(\"$name\");");
354             push(@function, "        if (${name}ValueIterator == argumentsEndIterator) {");
355             push(@function, "            protocolErrors->pushString(\"Protocol Error: Argument '$name' with type '$JSONType' was not found.\");");
356             push(@function, "        } else {");
357             push(@function, "            if (!${name}ValueIterator->second->as$JSONType(&$name)) {");
358             push(@function, "                protocolErrors->pushString(\"Protocol Error: Argument '$name' has wrong type. It should be '$JSONType'.\");");
359             push(@function, "            }");
360             push(@function, "        }");
361         }
362         push(@function, "    }");
363     }
364
365     # declare local variables for out arguments.
366     push(@function, map("    " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @outArgs));
367
368     my $args = join(", ", (map($_->name, @inArgs), map("&" . $_->name, @outArgs)));
369     push(@function, "    if (!protocolErrors->length())");
370     push(@function, "        $domainAccessor->$functionName($args);");
371     push(@function, "");
372
373     push(@function, "    // use InspectorFrontend as a marker of WebInspector availability");
374     push(@function, "    if ((callId || protocolErrors->length()) && m_inspectorController->hasFrontend()) {");
375     push(@function, "        RefPtr<InspectorObject> responseMessage = InspectorObject::create();");
376     push(@function, "        responseMessage->setNumber(\"seq\", callId);");
377     push(@function, "        responseMessage->setBoolean(\"success\", !protocolErrors->length());");
378     push(@function, "");
379     push(@function, "        if (protocolErrors->length())");
380     push(@function, "            responseMessage->setArray(\"errors\", protocolErrors);");
381     if (scalar(@outArgs)) {
382         push(@function, "        else {");
383         push(@function, "            RefPtr<InspectorObject> responseData = InspectorObject::create();");
384         push(@function, map("            responseData->set" . $typeTransform{$_->type}->{"JSONType"} . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs));
385         push(@function, "            responseMessage->setObject(\"data\", responseData);");
386         push(@function, "        }");
387     }
388     push(@function, "        m_inspectorController->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());");
389     push(@function, "    }");
390
391
392     push(@function, "}");
393     push(@function, "");
394     push(@backendMethodsImpl, @function);
395 }
396
397 sub generateBackendReportProtocolError
398 {
399     my $reportProtocolError = << "EOF";
400
401 void ${backendClassName}::reportProtocolError(const long callId, const String& errorText) const
402 {
403     RefPtr<InspectorObject> message = InspectorObject::create();
404     message->setNumber("seq", callId);
405     message->setBoolean("success", false);
406     RefPtr<InspectorArray> errors = InspectorArray::create();
407     errors->pushString(errorText);
408     message->setArray("errors", errors);
409     m_inspectorController->inspectorClient()->sendMessageToFrontend(message->toJSONString());
410 }
411 EOF
412     return split("\n", $reportProtocolError);
413 }
414
415
416 sub generateBackendDispatcher
417 {
418     my @body;
419     my @methods = map($backendMethods{$_}, keys %backendMethods);
420     my @mapEntries = map("        dispatchMap.add(${_}Cmd, &${backendClassName}::$_);", @methods);
421     my $mapEntries = join("\n", @mapEntries);
422
423     my $backendDispatcherBody = << "EOF";
424 void ${backendClassName}::dispatch(const String& message)
425 {
426     typedef void (${backendClassName}::*CallHandler)(long callId, InspectorObject* messageObject);
427     typedef HashMap<String, CallHandler> DispatchMap;
428     DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
429     long callId = 0;
430
431     if (dispatchMap.isEmpty()) {
432 $mapEntries
433     }
434
435     RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
436     if (!parsedMessage) {
437         reportProtocolError(callId, "Protocol Error: Invalid message format. Message should be in JSON format.");
438         return;
439     }
440
441     RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
442     if (!messageObject) {
443         reportProtocolError(callId, "Protocol Error: Invalid message format. The message should be a JSONified object.");
444         return;
445     }
446
447     RefPtr<InspectorValue> commandValue = messageObject->get("command");
448     if (!commandValue) {
449         reportProtocolError(callId, "Protocol Error: Invalid message format. 'command' property wasn't found.");
450         return;
451     }
452
453     String command;
454     if (!commandValue->asString(&command)) {
455         reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'command' property should be string.");
456         return;
457     }
458
459     RefPtr<InspectorValue> callIdValue = messageObject->get("seq");
460     if (!callIdValue) {
461         reportProtocolError(callId, "Protocol Error: Invalid message format. 'seq' property was not found in the request.");
462         return;
463     }
464
465     if (!callIdValue->asNumber(&callId)) {
466         reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'seq' property should be number.");
467         return;
468     }
469
470     HashMap<String, CallHandler>::iterator it = dispatchMap.find(command);
471     if (it == dispatchMap.end()) {
472         reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found."));
473         return;
474     }
475
476     ((*this).*it->second)(callId, messageObject.get());
477 }
478 EOF
479     return split("\n", $backendDispatcherBody);
480 }
481
482 sub generateBackendMessageParser
483 {
484     my $messageParserBody = << "EOF";
485 bool ${backendClassName}::getCommandName(const String& message, String* result)
486 {
487     RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
488     if (!value)
489         return false;
490
491     RefPtr<InspectorObject> object = value->asObject();
492     if (!object)
493         return false;
494
495     RefPtr<InspectorValue> commandValue = object->get("command");
496     if (!commandValue)
497         return false;
498
499     return commandValue->asString(result);
500 }
501
502 EOF
503     return split("\n", $messageParserBody);
504 }
505
506 sub generateBackendStubJS
507 {
508     my $interface = shift;
509     my @backendFunctions = grep(!$_->signature->extendedAttributes->{"notify"}, @{$interface->functions});
510     my @JSStubs;
511
512     foreach my $function (@backendFunctions) {
513         my $name = $function->signature->name;
514         my $domain = $function->signature->extendedAttributes->{"handler"};
515         my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . lc($typeTransform{$_->type}->{"JSONType"}) . "\"", grep($_->direction eq "in", @{$function->parameters})));
516         push(@JSStubs, "    this._registerDelegate('{" .
517             "\"seq\": 0, " .
518             "\"domain\": \"$domain\", " .
519             "\"command\": \"$name\", " .
520             "\"arguments\": {$argumentNames}" .
521         "}');");
522     }
523
524     my $JSStubs = join("\n", @JSStubs);
525     my $inspectorBackendStubJS = << "EOF";
526 $licenseTemplate
527
528 WebInspector.InspectorBackendStub = function()
529 {
530 $JSStubs
531 }
532
533 WebInspector.InspectorBackendStub.prototype = {
534     _registerDelegate: function(commandInfo)
535     {
536         var commandObject = JSON.parse(commandInfo);
537         this[commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo);
538     },
539
540     sendMessageToBackend: function()
541     {
542         var args = Array.prototype.slice.call(arguments);
543         var request = JSON.parse(args.shift());
544
545         for (var key in request.arguments) {
546             if (args.length === 0) {
547                 console.error("Protocol Error: Invalid number of arguments for 'InspectorBackend.%s' call. It should have the next arguments '%s'.", request.command, JSON.stringify(request.arguments));
548                 return;
549             }
550             var value = args.shift();
551             if (typeof value !== request.arguments[key]) {
552                 console.error("Protocol Error: Invalid type of argument '%s' for 'InspectorBackend.%s' call. It should be '%s' but it is '%s'.", key, request.command, request.arguments[key], typeof value);
553                 return;
554             }
555             request.arguments[key] = value;
556         }
557
558         if (args.length === 1) {
559             if (typeof args[0] !== "function" && typeof args[0] !== "undefined") {
560                 console.error("Protocol Error: Optional callback argument for 'InspectorBackend.%s' call should be a function but its type is '%s'.", request.command, typeof args[0]);
561                 return;
562             }
563             request.seq = WebInspector.Callback.wrap(args[0]);
564         }
565
566         var message = JSON.stringify(request);
567         InspectorFrontendHost.sendMessageToBackend(message);
568     }
569 }
570
571 InspectorBackend = new WebInspector.InspectorBackendStub();
572
573 EOF
574     return split("\n", $inspectorBackendStubJS);
575 }
576
577 sub generateHeader
578 {
579     my $className = shift;
580     my $types = shift;
581     my $constructor = shift;
582     my $constants = shift;
583     my $methods = shift;
584     my $footer = shift;
585
586     my $forwardHeaders = join("\n", sort(map("#include <" . $typeTransform{$_}->{"forwardHeader"} . ">", grep($typeTransform{$_}->{"forwardHeader"}, keys %{$types}))));
587     my $forwardDeclarations = join("\n", sort(map("class " . $typeTransform{$_}->{"forward"} . ";", grep($typeTransform{$_}->{"forward"}, keys %{$types}))));
588     my $constantDeclarations = join("\n", @{$constants});
589     my $methodsDeclarations = join("\n", keys %{$methods});
590
591     my $headerBody = << "EOF";
592 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
593 // Use of this source code is governed by a BSD-style license that can be
594 // found in the LICENSE file.
595 #ifndef ${className}_h
596 #define ${className}_h
597
598 ${forwardHeaders}
599
600 namespace $namespace {
601
602 $forwardDeclarations
603
604 class $className {
605 public:
606 $constructor
607
608 $constantDeclarations
609 $methodsDeclarations
610
611 private:
612 $footer
613 };
614
615 } // namespace $namespace
616 #endif // !defined(${className}_h)
617
618 EOF
619     return $headerBody;
620 }
621
622 sub generateSource
623 {
624     my $className = shift;
625     my $types = shift;
626     my $constants = shift;
627     my $methods = shift;
628
629     my @sourceContent = split("\r", $licenseTemplate);
630     push(@sourceContent, "\n#include \"config.h\"");
631     push(@sourceContent, "#include \"$className.h\"");
632     push(@sourceContent, "#include <wtf/text/StringConcatenate.h>");
633     push(@sourceContent, "");
634     push(@sourceContent, "#if ENABLE(INSPECTOR)");
635     push(@sourceContent, "");
636
637     my %headers;
638     foreach my $type (keys %{$types}) {
639         $headers{"#include \"" . $typeTransform{$type}->{"header"} . "\""} = 1 if !$typeTransform{$type}->{"header"} eq  "";
640     }
641     push(@sourceContent, sort keys %headers);
642     push(@sourceContent, "");
643     push(@sourceContent, "namespace $namespace {");
644     push(@sourceContent, "");
645     push (@sourceContent, join("\n", @{$constants}));
646     push(@sourceContent, "");
647     push(@sourceContent, @{$methods});
648     push(@sourceContent, "");
649     push(@sourceContent, "} // namespace $namespace");
650     push(@sourceContent, "");
651     push(@sourceContent, "#endif // ENABLE(INSPECTOR)");
652     push(@sourceContent, "");
653     return @sourceContent;
654 }
655
656 sub finish
657 {
658     my $object = shift;
659
660     open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp";
661     print $SOURCE join("\n", generateSource($frontendClassName, \%frontendTypes, \@frontendConstantDefinitions, \@frontendMethodsImpl));
662     close($SOURCE);
663     undef($SOURCE);
664
665     open(my $HEADER, ">$outputHeadersDir/$frontendClassName.h") || die "Couldn't open file $outputHeadersDir/$frontendClassName.h";
666     print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \@frontendConstantDeclarations, \%frontendMethods, $frontendFooter);
667     close($HEADER);
668     undef($HEADER);
669
670     open($SOURCE, ">$outputDir/$backendClassName.cpp") || die "Couldn't open file $outputDir/$backendClassName.cpp";
671     print $SOURCE join("\n", generateSource($backendClassName, \%backendTypes, \@backendConstantDefinitions, \@backendMethodsImpl));
672     close($SOURCE);
673     undef($SOURCE);
674
675     open($HEADER, ">$outputHeadersDir/$backendClassName.h") || die "Couldn't open file $outputHeadersDir/$backendClassName.h";
676     print $HEADER join("\n", generateHeader($backendClassName, \%backendTypes, $backendConstructor, \@backendConstantDeclarations, \%backendMethods, $backendFooter));
677     close($HEADER);
678     undef($HEADER);
679
680     open(my $JS_STUB, ">$outputDir/$backendJSStubName.js") || die "Couldn't open file $outputDir/$backendJSStubName.js";
681     print $JS_STUB join("\n", @backendStubJS);
682     close($JS_STUB);
683     undef($JS_STUB);
684 }
685
686 1;