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.
5 package CodeGeneratorInspector;
13 $typeTransform{"ApplicationCache"} = {
14 "forward" => "InspectorApplicationCacheAgent",
15 "header" => "InspectorApplicationCacheAgent.h",
16 "domainAccessor" => "m_inspectorAgent->applicationCacheAgent()",
18 $typeTransform{"CSS"} = {
19 "forward" => "InspectorCSSAgent",
20 "header" => "InspectorCSSAgent.h",
21 "domainAccessor" => "m_inspectorAgent->cssAgent()",
23 $typeTransform{"Console"} = {
24 "forward" => "InspectorConsoleAgent",
25 "header" => "InspectorConsoleAgent.h",
26 "domainAccessor" => "m_inspectorAgent->consoleAgent()",
28 $typeTransform{"Debugger"} = {
29 "forward" => "InspectorDebuggerAgent",
30 "header" => "InspectorDebuggerAgent.h",
31 "domainAccessor" => "m_inspectorAgent->debuggerAgent()",
33 $typeTransform{"BrowserDebugger"} = {
34 "forward" => "InspectorBrowserDebuggerAgent",
35 "header" => "InspectorBrowserDebuggerAgent.h",
36 "domainAccessor" => "m_inspectorAgent->browserDebuggerAgent()",
38 $typeTransform{"Database"} = {
39 "forward" => "InspectorDatabaseAgent",
40 "header" => "InspectorDatabaseAgent.h",
41 "domainAccessor" => "m_inspectorAgent->databaseAgent()",
43 $typeTransform{"DOM"} = {
44 "forward" => "InspectorDOMAgent",
45 "header" => "InspectorDOMAgent.h",
46 "domainAccessor" => "m_inspectorAgent->domAgent()",
48 $typeTransform{"DOMStorage"} = {
49 "forward" => "InspectorDOMStorageAgent",
50 "header" => "InspectorDOMStorageAgent.h",
51 "domainAccessor" => "m_inspectorAgent->domStorageAgent()",
53 $typeTransform{"FileSystem"} = {
54 "forward" => "InspectorFileSystemAgent",
55 "header" => "InspectorFileSystemAgent.h",
56 "domainAccessor" => "m_inspectorAgent->fileSystemAgent()",
58 $typeTransform{"Inspector"} = {
59 "forwardHeader" => "InspectorAgent.h",
60 "domainAccessor" => "m_inspectorAgent",
62 $typeTransform{"Network"} = {
63 "forward" => "InspectorResourceAgent",
64 "header" => "InspectorResourceAgent.h",
65 "domainAccessor" => "m_inspectorAgent->resourceAgent()",
67 $typeTransform{"Profiler"} = {
68 "forward" => "InspectorProfilerAgent",
69 "header" => "InspectorProfilerAgent.h",
70 "domainAccessor" => "m_inspectorAgent->profilerAgent()",
72 $typeTransform{"Runtime"} = {
73 "forward" => "InspectorRuntimeAgent",
74 "header" => "InspectorRuntimeAgent.h",
75 "domainAccessor" => "m_inspectorAgent->runtimeAgent()",
77 $typeTransform{"Timeline"} = {
78 "forward" => "InspectorTimelineAgent",
79 "header" => "InspectorTimelineAgent.h",
80 "domainAccessor" => "m_inspectorAgent->timelineAgent()",
83 $typeTransform{"Frontend"} = {
84 "forward" => "InspectorFrontend",
85 "header" => "InspectorFrontend.h",
87 $typeTransform{"InspectorClient"} = {
88 "forward" => "InspectorClient",
89 "header" => "InspectorClient.h",
91 $typeTransform{"PassRefPtr"} = {
92 "forwardHeader" => "wtf/PassRefPtr.h",
94 $typeTransform{"Object"} = {
95 "param" => "PassRefPtr<InspectorObject>",
96 "variable" => "RefPtr<InspectorObject>",
97 "defaultValue" => "InspectorObject::create()",
98 "forward" => "InspectorObject",
99 "header" => "InspectorValues.h",
100 "JSONType" => "Object",
101 "JSType" => "object",
104 $typeTransform{"Array"} = {
105 "param" => "PassRefPtr<InspectorArray>",
106 "variable" => "RefPtr<InspectorArray>",
107 "defaultValue" => "InspectorArray::create()",
108 "forward" => "InspectorArray",
109 "header" => "InspectorValues.h",
110 "JSONType" => "Array",
111 "JSType" => "object",
112 "DocType" => "array of %s"
114 $typeTransform{"Value"} = {
115 "param" => "PassRefPtr<InspectorValue>",
116 "variable" => "RefPtr<InspectorValue>",
117 "defaultValue" => "InspectorValue::null()",
118 "forward" => "InspectorValue",
119 "header" => "InspectorValues.h",
120 "JSONType" => "Value",
124 $typeTransform{"String"} = {
125 "param" => "const String&",
126 "variable" => "String",
127 "return" => "String",
128 "defaultValue" => "\"\"",
129 "forwardHeader" => "PlatformString.h",
130 "header" => "PlatformString.h",
131 "JSONType" => "String",
134 $typeTransform{"long"} = {
136 "variable" => "long",
137 "defaultValue" => "0",
140 "JSONType" => "Number",
143 $typeTransform{"int"} = {
146 "defaultValue" => "0",
149 "JSONType" => "Number",
152 $typeTransform{"unsigned long"} = {
153 "param" => "unsigned long",
154 "variable" => "unsigned long",
155 "defaultValue" => "0u",
158 "JSONType" => "Number",
161 $typeTransform{"unsigned int"} = {
162 "param" => "unsigned int",
163 "variable" => "unsigned int",
164 "defaultValue" => "0u",
167 "JSONType" => "Number",
170 $typeTransform{"double"} = {
172 "variable" => "double",
173 "defaultValue" => "0.0",
176 "JSONType" => "Number",
179 $typeTransform{"boolean"} = {
182 "defaultValue" => "false",
185 "JSONType" => "Boolean",
186 "JSType" => "boolean"
188 $typeTransform{"void"} = {
193 # Default License Templates
195 my $licenseTemplate = << "EOF";
196 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
197 // Use of this source code is governed by a BSD-style license that can be
198 // found in the LICENSE file.
203 my $outputHeadersDir;
204 my $writeDependencies;
209 my $backendClassName;
210 my $backendJSStubName;
213 my @backendMethodsImpl;
214 my %backendMethodSignatures;
215 my $backendConstructor;
216 my @backendConstantDeclarations;
217 my @backendConstantDefinitions;
221 my $frontendClassName;
224 my @frontendMethodsImpl;
225 my %frontendMethodSignatures;
226 my $frontendConstructor;
227 my @frontendConstantDeclarations;
228 my @frontendConstantDefinitions;
231 my @documentationToc;
232 my @documentationLines;
234 # Default constructor
240 $codeGenerator = shift;
242 $outputHeadersDir = shift;
243 shift; # $useLayerOnTop
244 shift; # $preprocessor
245 $writeDependencies = shift;
248 bless($reference, $object);
252 # Params: 'idlDocument' struct
256 my $dataNode = shift;
258 $namespace = $dataNode->module;
259 $namespace =~ s/core/WebCore/;
262 # Params: 'idlDocument' struct
263 sub GenerateInterface
266 my $interface = shift;
269 my $className = $interface->name;
271 $frontendClassName = "InspectorFrontend";
272 $frontendConstructor = " ${frontendClassName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }";
273 $frontendFooter = " private:\n InspectorClient* m_inspectorClient;";
274 $frontendTypes{"String"} = 1;
275 $frontendTypes{"InspectorClient"} = 1;
276 $frontendTypes{"PassRefPtr"} = 1;
278 $backendClassName = "InspectorBackendDispatcher";
279 $backendJSStubName = "InspectorBackendStub";
281 push(@backendHead, " ${backendClassName}(InspectorAgent* inspectorAgent) : m_inspectorAgent(inspectorAgent) { }");
282 push(@backendHead, " void reportProtocolError(const long callId, const String& errorText) const;");
283 push(@backendHead, " void dispatch(const String& message);");
284 push(@backendHead, " static bool getCommandName(const String& message, String* result);");
285 $backendConstructor = join("\n", @backendHead);
286 $backendFooter = " InspectorAgent* m_inspectorAgent;";
287 $backendTypes{"Inspector"} = 1;
288 $backendTypes{"InspectorClient"} = 1;
289 $backendTypes{"PassRefPtr"} = 1;
290 $backendTypes{"Object"} = 1;
292 generateFunctions($interface);
295 sub generateFunctions
297 my $interface = shift;
299 foreach my $function (@{$interface->functions}) {
300 if ($function->signature->extendedAttributes->{"event"}) {
301 generateFrontendFunction($interface, $function);
303 generateBackendFunction($interface, $function);
307 push(@documentationToc, "<li><a href='#" . $interface->name . "'>" . $interface->name . "</a></li>");
308 push(@documentationLines, "<h2 id='" . $interface->name . "'><a name=" . $interface->name . "></a>" . $interface->name . "</h2>");
310 push(@documentationLines, "<h3>Events</h3>");
311 foreach my $function (grep($_->signature->extendedAttributes->{"event"}, @{$interface->functions}) ) {
312 generateDocumentationEvent($interface, $function);
315 push(@documentationLines, "<h3>Commands</h3>");
316 foreach my $function (grep(!$_->signature->extendedAttributes->{"event"}, @{$interface->functions})) {
317 generateDocumentationCommand($interface, $function);
320 collectBackendJSStubFunctions($interface);
323 sub generateFrontendFunction
325 my $interface = shift;
326 my $function = shift;
328 my $functionName = $function->signature->name;
330 my $domain = $interface->name;
331 my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); # just keep only out parameters for frontend interface.
332 map($frontendTypes{$_->type} = 1, @argsFiltered); # register required types.
333 my $arguments = join(", ", map(typeTraits($_->type, "param") . " " . $_->name, @argsFiltered)); # prepare arguments for function signature.
335 my $signature = " void ${functionName}(${arguments});";
336 !$frontendMethodSignatures{${signature}} || die "Duplicate frontend function was detected for signature '$signature'.";
337 $frontendMethodSignatures{${signature}} = 1;
338 push(@frontendMethods, $signature);
341 push(@function, "void ${frontendClassName}::${functionName}(${arguments})");
342 push(@function, "{");
343 push(@function, " RefPtr<InspectorObject> ${functionName}Message = InspectorObject::create();");
344 push(@function, " ${functionName}Message->setString(\"type\", \"event\");");
345 push(@function, " ${functionName}Message->setString(\"domain\", \"$domain\");");
346 push(@function, " ${functionName}Message->setString(\"event\", \"$functionName\");");
347 push(@function, " RefPtr<InspectorObject> payloadDataObject = InspectorObject::create();");
348 my @pushArguments = map(" payloadDataObject->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered);
349 push(@function, @pushArguments);
350 push(@function, " ${functionName}Message->setObject(\"data\", payloadDataObject);");
351 push(@function, " m_inspectorClient->sendMessageToFrontend(${functionName}Message->toJSONString());");
353 push(@function, "}");
355 push(@frontendMethodsImpl, @function);
358 sub generateDocumentationEvent
360 my $interface = shift;
361 my $function = shift;
363 my $functionName = $function->signature->name;
364 my $domain = $interface->name;
366 my @argsFiltered = grep($_->direction eq "out", @{$function->parameters});
369 push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>");
370 my $doc = $function->signature->extendedAttributes->{"doc"};
375 push(@lines, "<pre style='background: lightGrey; padding: 10px'>");
377 push(@lines, " seq: <number>,");
378 push(@lines, " type: \"event\",");
379 push(@lines, " domain: \"$domain\",");
380 if (scalar(@argsFiltered)) {
381 push(@lines, " event: \"${functionName}\",");
382 push(@lines, " data: {");
384 foreach my $parameter (@argsFiltered) {
385 push(@parameters, " " . parameterDocLine($parameter));
387 push(@lines, join(",\n", @parameters));
390 push(@lines, " event: \"${functionName}\"");
393 push(@lines, "</pre>");
394 push(@documentationLines, @lines);
400 $value =~ s/\b(\w)/\U$1/g; # make a camel-case name for type name
405 sub generateBackendFunction
407 my $interface = shift;
408 my $function = shift;
410 my $functionName = $function->signature->name;
411 my $fullQualifiedFunctionName = $interface->name . "_" . $function->signature->name;
413 push(@backendConstantDeclarations, " static const char* ${fullQualifiedFunctionName}Cmd;");
414 push(@backendConstantDefinitions, "const char* ${backendClassName}::${fullQualifiedFunctionName}Cmd = \"${functionName}\";");
416 map($backendTypes{$_->type} = 1, @{$function->parameters}); # register required types
417 my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters});
418 my @outArgs = grep($_->direction eq "out", @{$function->parameters});
420 my $signature = " void ${fullQualifiedFunctionName}(long callId, InspectorObject* requestMessageObject);";
421 !$backendMethodSignatures{${signature}} || die "Duplicate function was detected for signature '$signature'.";
422 $backendMethodSignatures{${signature}} = "$fullQualifiedFunctionName";
423 push(@backendMethods, ${signature});
426 my $requestMessageObject = scalar(@inArgs) ? " requestMessageObject" : "";
427 push(@function, "void ${backendClassName}::${fullQualifiedFunctionName}(long callId, InspectorObject*$requestMessageObject)");
428 push(@function, "{");
429 push(@function, " RefPtr<InspectorArray> protocolErrors = InspectorArray::create();");
432 my $domain = $interface->name;
433 my $domainAccessor = typeTraits($domain, "domainAccessor");
434 $backendTypes{$domain} = 1;
435 push(@function, " if (!$domainAccessor)");
436 push(@function, " protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");");
439 # declare local variables for out arguments.
440 push(@function, map(" " . typeTraits($_->type, "variable") . " " . $_->name . " = " . typeTraits($_->type, "defaultValue") . ";", @outArgs));
443 if (scalar(@inArgs)) {
444 push(@function, " if (RefPtr<InspectorObject> argumentsContainer = requestMessageObject->getObject(\"arguments\")) {");
446 foreach my $parameter (@inArgs) {
447 my $name = $parameter->name;
448 my $type = $parameter->type;
449 my $typeString = camelCase($parameter->type);
450 push(@function, " " . typeTraits($type, "variable") . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());");
456 push(@function, "$indent ErrorString error;");
457 my $args = join(", ", ("&error", map($_->name, @inArgs), map("&" . $_->name, @outArgs)));
458 push(@function, "$indent if (!protocolErrors->length())");
459 push(@function, "$indent $domainAccessor->$functionName($args);");
460 push(@function, "$indent if (error.length())");
461 push(@function, "$indent protocolErrors->pushString(error);");
462 if (scalar(@inArgs)) {
463 push(@function, " } else {");
464 push(@function, " protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");");
465 push(@function, " }");
468 push(@function, " // use InspectorFrontend as a marker of WebInspector availability");
469 push(@function, " if ((callId || protocolErrors->length()) && m_inspectorAgent->hasFrontend()) {");
470 push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();");
471 push(@function, " responseMessage->setNumber(\"seq\", callId);");
472 push(@function, " responseMessage->setString(\"domain\", \"$domain\");");
473 push(@function, " responseMessage->setBoolean(\"success\", !protocolErrors->length());");
475 push(@function, " if (protocolErrors->length())");
476 push(@function, " responseMessage->setArray(\"errors\", protocolErrors);");
477 if (scalar(@outArgs)) {
478 push(@function, " else {");
479 push(@function, " RefPtr<InspectorObject> responseData = InspectorObject::create();");
480 push(@function, map(" responseData->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs));
481 push(@function, " responseMessage->setObject(\"data\", responseData);");
482 push(@function, " }");
484 push(@function, " m_inspectorAgent->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());");
485 push(@function, " }");
488 push(@function, "}");
490 push(@backendMethodsImpl, @function);
493 sub generateDocumentationCommand
495 my $interface = shift;
496 my $function = shift;
498 my $functionName = $function->signature->name;
499 my $domain = $interface->name;
503 push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>");
504 my $doc = $function->signature->extendedAttributes->{"doc"};
509 my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters});
510 push(@lines, "<pre style='background: lightGrey; padding: 10px'>");
511 push(@lines, "request: {");
512 push(@lines, " seq: <number>,");
513 push(@lines, " type: \"request\",");
514 push(@lines, " domain: \"" . $interface->name . "\",");
515 if (scalar(@inArgs)) {
516 push(@lines, " command: \"${functionName}\",");
517 push(@lines, " arguments: {");
519 foreach my $parameter (@inArgs) {
520 push(@parameters, " " . parameterDocLine($parameter));
522 push(@lines, join(",\n", @parameters));
525 push(@lines, " command: \"${functionName}\"");
529 my @outArgs = grep($_->direction eq "out", @{$function->parameters});
531 push(@lines, "response: {");
532 push(@lines, " seq: <number>,");
533 if (scalar(@outArgs)) {
534 push(@lines, " type: \"response\",");
535 push(@lines, " body: {");
537 foreach my $parameter (@outArgs) {
538 push(@parameters, " " . parameterDocLine($parameter));
540 push(@lines, join(",\n", @parameters));
543 push(@lines, " type: \"response\"");
546 push(@lines, "</pre>");
548 push(@documentationLines, @lines);
551 sub generateBackendReportProtocolError
553 my $reportProtocolError = << "EOF";
555 void ${backendClassName}::reportProtocolError(const long callId, const String& errorText) const
557 RefPtr<InspectorObject> message = InspectorObject::create();
558 message->setNumber("seq", callId);
559 message->setBoolean("success", false);
560 RefPtr<InspectorArray> errors = InspectorArray::create();
561 errors->pushString(errorText);
562 message->setArray("errors", errors);
563 m_inspectorAgent->inspectorClient()->sendMessageToFrontend(message->toJSONString());
566 return split("\n", $reportProtocolError);
569 sub generateArgumentGetters
572 my $json = typeTraits($type, "JSONType");
573 my $variable = typeTraits($type, "variable");
574 my $defaultValue = typeTraits($type, "defaultValue");
575 my $return = typeTraits($type, "return") ? typeTraits($type, "return") : typeTraits($type, "param");
577 my $typeString = camelCase($type);
578 push(@backendConstantDeclarations, " $return get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors);");
579 my $getterBody = << "EOF";
581 $return InspectorBackendDispatcher::get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors)
584 ASSERT(protocolErrors);
586 $variable value = $defaultValue;
587 InspectorObject::const_iterator end = object->end();
588 InspectorObject::const_iterator valueIterator = object->find(name);
590 if (valueIterator == end)
591 protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' with type '$json' was not found.", name.utf8().data()));
593 if (!valueIterator->second->as$json(&value))
594 protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' has wrong type. It should be '$json'.", name.utf8().data()));
600 return split("\n", $getterBody);
603 sub generateBackendDispatcher
606 my @mapEntries = map(" dispatchMap.add(${_}Cmd, &${backendClassName}::$_);", map ($backendMethodSignatures{$_}, @backendMethods));
607 my $mapEntries = join("\n", @mapEntries);
609 my $backendDispatcherBody = << "EOF";
610 void ${backendClassName}::dispatch(const String& message)
612 typedef void (${backendClassName}::*CallHandler)(long callId, InspectorObject* messageObject);
613 typedef HashMap<String, CallHandler> DispatchMap;
614 DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
617 if (dispatchMap.isEmpty()) {
621 RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
622 if (!parsedMessage) {
623 reportProtocolError(callId, "Protocol Error: Invalid message format. Message should be in JSON format.");
627 RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
628 if (!messageObject) {
629 reportProtocolError(callId, "Protocol Error: Invalid message format. The message should be a JSONified object.");
633 RefPtr<InspectorValue> commandValue = messageObject->get("command");
635 reportProtocolError(callId, "Protocol Error: Invalid message format. 'command' property wasn't found.");
640 if (!commandValue->asString(&command)) {
641 reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'command' property should be string.");
645 RefPtr<InspectorValue> callIdValue = messageObject->get("seq");
647 reportProtocolError(callId, "Protocol Error: Invalid message format. 'seq' property was not found in the request.");
651 if (!callIdValue->asNumber(&callId)) {
652 reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'seq' property should be number.");
656 HashMap<String, CallHandler>::iterator it = dispatchMap.find(command);
657 if (it == dispatchMap.end()) {
658 reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found."));
662 ((*this).*it->second)(callId, messageObject.get());
665 return split("\n", $backendDispatcherBody);
668 sub generateBackendMessageParser
670 my $messageParserBody = << "EOF";
671 bool ${backendClassName}::getCommandName(const String& message, String* result)
673 RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
677 RefPtr<InspectorObject> object = value->asObject();
681 RefPtr<InspectorValue> commandValue = object->get("command");
685 return commandValue->asString(result);
688 return split("\n", $messageParserBody);
691 sub collectBackendJSStubFunctions
693 my $interface = shift;
694 my @functions = grep(!$_->signature->extendedAttributes->{"event"}, @{$interface->functions});
695 my $domain = $interface->name;
697 foreach my $function (@functions) {
698 my $name = $function->signature->name;
699 my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . typeTraits($_->type, "JSType") . "\"", grep($_->direction eq "in", @{$function->parameters})));
700 push(@backendJSStubs, " this._registerDelegate('{" .
702 "\"domain\": \"$domain\", " .
703 "\"command\": \"$name\", " .
704 "\"arguments\": {$argumentNames}" .
709 sub generateBackendStubJS
711 my $JSStubs = join("\n", @backendJSStubs);
712 my $inspectorBackendStubJS = << "EOF";
715 InspectorBackendStub = function()
717 this._lastCallbackId = 1;
718 this._pendingResponsesCount = 0;
719 this._callbacks = {};
720 this._domainDispatchers = {};
724 InspectorBackendStub.prototype = {
725 _wrap: function(callback)
727 var callbackId = this._lastCallbackId++;
728 ++this._pendingResponsesCount;
729 this._callbacks[callbackId] = callback || function() {};
733 _registerDelegate: function(commandInfo)
735 var commandObject = JSON.parse(commandInfo);
736 var agentName = commandObject.domain + "Agent";
737 if (!window[agentName])
738 window[agentName] = {};
739 window[agentName][commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo);
742 sendMessageToBackend: function()
744 var args = Array.prototype.slice.call(arguments);
745 var request = JSON.parse(args.shift());
747 for (var key in request.arguments) {
748 if (args.length === 0) {
749 console.error("Protocol Error: Invalid number of arguments for '" + request.domain + "Agent." + request.command + "' call. It should have the next arguments '" + JSON.stringify(request.arguments) + "'.");
752 var value = args.shift();
753 if (request.arguments[key] && typeof value !== request.arguments[key]) {
754 console.error("Protocol Error: Invalid type of argument '" + key + "' for '" + request.domain + "Agent." + request.command + "' call. It should be '" + request.arguments[key] + "' but it is '" + typeof value + "'.");
757 request.arguments[key] = value;
761 if (args.length === 1) {
762 if (typeof args[0] !== "function" && typeof args[0] !== "undefined") {
763 console.error("Protocol Error: Optional callback argument for '" + request.domain + "Agent." + request.command + "' call should be a function but its type is '" + typeof args[0] + "'.");
768 request.seq = this._wrap(callback || function() {});
770 if (window.dumpInspectorProtocolMessages)
771 console.log("frontend: " + JSON.stringify(request));
773 var message = JSON.stringify(request);
774 InspectorFrontendHost.sendMessageToBackend(message);
777 registerDomainDispatcher: function(domain, dispatcher)
779 this._domainDispatchers[domain] = dispatcher;
782 dispatch: function(message)
784 if (window.dumpInspectorProtocolMessages)
785 console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message)));
787 var messageObject = (typeof message === "string") ? JSON.parse(message) : message;
790 if (messageObject.data)
791 for (var key in messageObject.data)
792 arguments.push(messageObject.data[key]);
794 if ("seq" in messageObject) { // just a response for some request
795 if (messageObject.success)
796 this._callbacks[messageObject.seq].apply(null, arguments);
798 this.reportProtocolError(messageObject);
800 --this._pendingResponsesCount;
801 delete this._callbacks[messageObject.seq];
803 if (this._scripts && !this._pendingResponsesCount)
804 this.runAfterPendingDispatches();
809 if (messageObject.type === "event") {
810 if (!(messageObject.domain in this._domainDispatchers)) {
811 console.error("Protocol Error: the message is for non-existing domain '" + messageObject.domain + "'");
814 var dispatcher = this._domainDispatchers[messageObject.domain];
815 if (!(messageObject.event in dispatcher)) {
816 console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.domain + "." + messageObject.event + "'");
819 dispatcher[messageObject.event].apply(dispatcher, arguments);
823 reportProtocolError: function(messageObject)
825 console.error("Protocol Error: InspectorBackend request with seq = " + messageObject.seq + " failed.");
826 for (var i = 0; i < messageObject.errors.length; ++i)
827 console.error(" " + messageObject.errors[i]);
830 runAfterPendingDispatches: function(script)
836 this._scripts.push(script);
838 if (!this._pendingResponsesCount) {
839 var scripts = this._scripts;
841 for (var id = 0; id < scripts.length; ++id)
842 scripts[id].call(this);
847 InspectorBackend = new InspectorBackendStub();
850 return split("\n", $inspectorBackendStubJS);
855 my $className = shift;
857 my $constructor = shift;
858 my $constants = shift;
862 my $forwardHeaders = join("\n", sort(map("#include <" . typeTraits($_, "forwardHeader") . ">", grep(typeTraits($_, "forwardHeader"), keys %{$types}))));
863 my $forwardDeclarations = join("\n", sort(map("class " . typeTraits($_, "forward") . ";", grep(typeTraits($_, "forward"), keys %{$types}))));
864 my $constantDeclarations = join("\n", @{$constants});
865 my $methodsDeclarations = join("\n", @{$methods});
867 my $headerBody = << "EOF";
868 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
869 // Use of this source code is governed by a BSD-style license that can be
870 // found in the LICENSE file.
871 #ifndef ${className}_h
872 #define ${className}_h
876 namespace $namespace {
880 typedef String ErrorString;
886 $constantDeclarations
892 } // namespace $namespace
893 #endif // !defined(${className}_h)
901 my $className = shift;
903 my $constants = shift;
906 my @sourceContent = split("\r", $licenseTemplate);
907 push(@sourceContent, "\n#include \"config.h\"");
908 push(@sourceContent, "#include \"$className.h\"");
909 push(@sourceContent, "#include <wtf/text/StringConcatenate.h>");
910 push(@sourceContent, "#include <wtf/text/CString.h>");
911 push(@sourceContent, "");
912 push(@sourceContent, "#if ENABLE(INSPECTOR)");
913 push(@sourceContent, "");
916 foreach my $type (keys %{$types}) {
917 $headers{"#include \"" . typeTraits($type, "header") . "\""} = 1 if !typeTraits($type, "header") eq "";
919 push(@sourceContent, sort keys %headers);
920 push(@sourceContent, "");
921 push(@sourceContent, "namespace $namespace {");
922 push(@sourceContent, "");
923 push(@sourceContent, join("\n", @{$constants}));
924 push(@sourceContent, "");
925 push(@sourceContent, @{$methods});
926 push(@sourceContent, "");
927 push(@sourceContent, "} // namespace $namespace");
928 push(@sourceContent, "");
929 push(@sourceContent, "#endif // ENABLE(INSPECTOR)");
930 push(@sourceContent, "");
931 return @sourceContent;
938 return $typeTransform{$type}->{$trait};
943 my $parameter = shift;
944 my $subtype = $parameter->extendedAttributes->{"type"};
946 my $pattern = typeTraits($parameter->type, "DocType");
947 return sprintf($pattern, "<$subtype>");
950 my $subtypeRef = $parameter->extendedAttributes->{"typeRef"};
952 my $pattern = typeTraits($parameter->type, "DocType");
953 return sprintf($pattern, "<<a href='#$subtypeRef'>" . $subtypeRef . "</a>>");
956 return "<" . typeTraits($parameter->type, "JSType") . ">";
961 my $parameter = shift;
963 my $result = $parameter->name . ": " . parameterDocType($parameter);
964 my $doc = $parameter->extendedAttributes->{"doc"};
966 $result = $result . " // " . $doc;
975 push(@backendMethodsImpl, generateBackendDispatcher());
976 push(@backendMethodsImpl, generateBackendReportProtocolError());
978 open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp";
979 print $SOURCE join("\n", generateSource($frontendClassName, \%frontendTypes, \@frontendConstantDefinitions, \@frontendMethodsImpl));
983 open(my $HEADER, ">$outputHeadersDir/$frontendClassName.h") || die "Couldn't open file $outputHeadersDir/$frontendClassName.h";
984 print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \@frontendConstantDeclarations, \@frontendMethods, $frontendFooter);
988 # Make dispatcher methods private on the backend.
989 push(@backendConstantDeclarations, "");
990 push(@backendConstantDeclarations, "private:");
992 foreach my $type (keys %backendTypes) {
993 if (typeTraits($type, "JSONType")) {
994 push(@backendMethodsImpl, generateArgumentGetters($type));
998 push(@backendMethodsImpl, generateBackendMessageParser());
999 push(@backendMethodsImpl, "");
1001 push(@backendConstantDeclarations, "");
1003 open($SOURCE, ">$outputDir/$backendClassName.cpp") || die "Couldn't open file $outputDir/$backendClassName.cpp";
1004 print $SOURCE join("\n", generateSource($backendClassName, \%backendTypes, \@backendConstantDefinitions, \@backendMethodsImpl));
1008 open($HEADER, ">$outputHeadersDir/$backendClassName.h") || die "Couldn't open file $outputHeadersDir/$backendClassName.h";
1009 print $HEADER join("\n", generateHeader($backendClassName, \%backendTypes, $backendConstructor, \@backendConstantDeclarations, \@backendMethods, $backendFooter));
1013 open(my $JS_STUB, ">$outputDir/$backendJSStubName.js") || die "Couldn't open file $outputDir/$backendJSStubName.js";
1014 print $JS_STUB join("\n", generateBackendStubJS());
1018 open(my $DOCS, ">$outputDir/WebInspectorProtocol.html") || die "Couldn't open file $outputDir/WebInspectorProtocol.html";
1019 print $DOCS "<ol class='toc' style='list-style: none; padding: 0'>";
1020 print $DOCS join("\n", @documentationToc);
1021 print $DOCS "</ol>";
1022 print $DOCS join("\n", @documentationLines);