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{"InjectedScript"} = {
59 "forwardHeader" => "InjectedScriptHost.h",
60 "domainAccessor" => "m_inspectorAgent->injectedScriptAgent()",
62 $typeTransform{"Inspector"} = {
63 "forwardHeader" => "InspectorAgent.h",
64 "domainAccessor" => "m_inspectorAgent",
66 $typeTransform{"Network"} = {
67 "forward" => "InspectorResourceAgent",
68 "header" => "InspectorResourceAgent.h",
69 "domainAccessor" => "m_inspectorAgent->resourceAgent()",
71 $typeTransform{"Profiler"} = {
72 "forward" => "InspectorProfilerAgent",
73 "header" => "InspectorProfilerAgent.h",
74 "domainAccessor" => "m_inspectorAgent->profilerAgent()",
76 $typeTransform{"Runtime"} = {
77 "forward" => "InspectorRuntimeAgent",
78 "header" => "InspectorRuntimeAgent.h",
79 "domainAccessor" => "m_inspectorAgent->runtimeAgent()",
82 $typeTransform{"Frontend"} = {
83 "forward" => "InspectorFrontend",
84 "header" => "InspectorFrontend.h",
86 $typeTransform{"InspectorClient"} = {
87 "forward" => "InspectorClient",
88 "header" => "InspectorClient.h",
90 $typeTransform{"PassRefPtr"} = {
91 "forwardHeader" => "wtf/PassRefPtr.h",
93 $typeTransform{"Object"} = {
94 "param" => "PassRefPtr<InspectorObject>",
95 "variable" => "RefPtr<InspectorObject>",
96 "defaultValue" => "InspectorObject::create()",
97 "forward" => "InspectorObject",
98 "header" => "InspectorValues.h",
99 "JSONType" => "Object",
100 "JSType" => "object",
103 $typeTransform{"Array"} = {
104 "param" => "PassRefPtr<InspectorArray>",
105 "variable" => "RefPtr<InspectorArray>",
106 "defaultValue" => "InspectorArray::create()",
107 "forward" => "InspectorArray",
108 "header" => "InspectorValues.h",
109 "JSONType" => "Array",
110 "JSType" => "object",
111 "DocType" => "array of %s"
113 $typeTransform{"Value"} = {
114 "param" => "PassRefPtr<InspectorValue>",
115 "variable" => "RefPtr<InspectorValue>",
116 "defaultValue" => "InspectorValue::null()",
117 "forward" => "InspectorValue",
118 "header" => "InspectorValues.h",
119 "JSONType" => "Value",
123 $typeTransform{"String"} = {
124 "param" => "const String&",
125 "variable" => "String",
126 "return" => "String",
127 "defaultValue" => "\"\"",
128 "forwardHeader" => "PlatformString.h",
129 "header" => "PlatformString.h",
130 "JSONType" => "String",
133 $typeTransform{"long"} = {
135 "variable" => "long",
136 "defaultValue" => "0",
139 "JSONType" => "Number",
142 $typeTransform{"int"} = {
145 "defaultValue" => "0",
148 "JSONType" => "Number",
151 $typeTransform{"unsigned long"} = {
152 "param" => "unsigned long",
153 "variable" => "unsigned long",
154 "defaultValue" => "0u",
157 "JSONType" => "Number",
160 $typeTransform{"unsigned int"} = {
161 "param" => "unsigned int",
162 "variable" => "unsigned int",
163 "defaultValue" => "0u",
166 "JSONType" => "Number",
169 $typeTransform{"double"} = {
171 "variable" => "double",
172 "defaultValue" => "0.0",
175 "JSONType" => "Number",
178 $typeTransform{"boolean"} = {
181 "defaultValue" => "false",
184 "JSONType" => "Boolean",
185 "JSType" => "boolean"
187 $typeTransform{"void"} = {
192 # Default License Templates
194 my $licenseTemplate = << "EOF";
195 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
196 // Use of this source code is governed by a BSD-style license that can be
197 // found in the LICENSE file.
202 my $outputHeadersDir;
203 my $writeDependencies;
208 my $backendClassName;
209 my $backendJSStubName;
212 my @backendMethodsImpl;
213 my %backendMethodSignatures;
214 my $backendConstructor;
215 my @backendConstantDeclarations;
216 my @backendConstantDefinitions;
220 my $frontendClassName;
223 my @frontendMethodsImpl;
224 my %frontendMethodSignatures;
225 my $frontendConstructor;
226 my @frontendConstantDeclarations;
227 my @frontendConstantDefinitions;
230 my @documentationToc;
231 my @documentationLines;
233 # Default constructor
239 $codeGenerator = shift;
241 $outputHeadersDir = shift;
242 shift; # $useLayerOnTop
243 shift; # $preprocessor
244 $writeDependencies = shift;
247 bless($reference, $object);
251 # Params: 'idlDocument' struct
255 my $dataNode = shift;
257 $namespace = $dataNode->module;
258 $namespace =~ s/core/WebCore/;
261 # Params: 'idlDocument' struct
262 sub GenerateInterface
265 my $interface = shift;
268 my $className = $interface->name;
270 $frontendClassName = "InspectorFrontend";
271 $frontendConstructor = " ${frontendClassName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }";
272 $frontendFooter = " private:\n InspectorClient* m_inspectorClient;";
273 $frontendTypes{"String"} = 1;
274 $frontendTypes{"InspectorClient"} = 1;
275 $frontendTypes{"PassRefPtr"} = 1;
277 $backendClassName = "InspectorBackendDispatcher";
278 $backendJSStubName = "InspectorBackendStub";
280 push(@backendHead, " ${backendClassName}(InspectorAgent* inspectorAgent) : m_inspectorAgent(inspectorAgent) { }");
281 push(@backendHead, " void reportProtocolError(const long callId, const String& errorText) const;");
282 push(@backendHead, " void dispatch(const String& message);");
283 push(@backendHead, " static bool getCommandName(const String& message, String* result);");
284 $backendConstructor = join("\n", @backendHead);
285 $backendFooter = " InspectorAgent* m_inspectorAgent;";
286 $backendTypes{"Inspector"} = 1;
287 $backendTypes{"InspectorClient"} = 1;
288 $backendTypes{"PassRefPtr"} = 1;
289 $backendTypes{"Object"} = 1;
291 generateFunctions($interface);
294 sub generateFunctions
296 my $interface = shift;
298 foreach my $function (@{$interface->functions}) {
299 if ($function->signature->extendedAttributes->{"notify"}) {
300 generateFrontendFunction($interface, $function);
302 generateBackendFunction($interface, $function);
306 push(@documentationToc, "<li><a href='#" . $interface->name . "'>" . $interface->name . "</a></li>");
307 push(@documentationLines, "<h2 id='" . $interface->name . "'><a name=" . $interface->name . "></a>" . $interface->name . "</h2>");
309 push(@documentationLines, "<h3>Events</h3>");
310 foreach my $function (grep($_->signature->extendedAttributes->{"notify"}, @{$interface->functions}) ) {
311 generateDocumentationEvent($interface, $function);
314 push(@documentationLines, "<h3>Commands</h3>");
315 foreach my $function (grep(!$_->signature->extendedAttributes->{"notify"}, @{$interface->functions})) {
316 generateDocumentationCommand($interface, $function);
319 collectBackendJSStubFunctions($interface);
322 sub generateFrontendFunction
324 my $interface = shift;
325 my $function = shift;
327 my $functionName = $function->signature->name;
329 my $domain = $interface->name;
330 my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); # just keep only out parameters for frontend interface.
331 map($frontendTypes{$_->type} = 1, @argsFiltered); # register required types.
332 my $arguments = join(", ", map(typeTraits($_->type, "param") . " " . $_->name, @argsFiltered)); # prepare arguments for function signature.
334 my $signature = " void ${functionName}(${arguments});";
335 !$frontendMethodSignatures{${signature}} || die "Duplicate frontend function was detected for signature '$signature'.";
336 $frontendMethodSignatures{${signature}} = 1;
337 push(@frontendMethods, $signature);
340 push(@function, "void ${frontendClassName}::${functionName}(${arguments})");
341 push(@function, "{");
342 push(@function, " RefPtr<InspectorObject> ${functionName}Message = InspectorObject::create();");
343 push(@function, " ${functionName}Message->setString(\"type\", \"event\");");
344 push(@function, " ${functionName}Message->setString(\"domain\", \"$domain\");");
345 push(@function, " ${functionName}Message->setString(\"event\", \"$functionName\");");
346 push(@function, " RefPtr<InspectorObject> payloadDataObject = InspectorObject::create();");
347 my @pushArguments = map(" payloadDataObject->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered);
348 push(@function, @pushArguments);
349 push(@function, " ${functionName}Message->setObject(\"data\", payloadDataObject);");
350 push(@function, " m_inspectorClient->sendMessageToFrontend(${functionName}Message->toJSONString());");
352 push(@function, "}");
354 push(@frontendMethodsImpl, @function);
357 sub generateDocumentationEvent
359 my $interface = shift;
360 my $function = shift;
362 my $functionName = $function->signature->name;
363 my $domain = $interface->name;
365 my @argsFiltered = grep($_->direction eq "out", @{$function->parameters});
368 push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>");
369 my $doc = $function->signature->extendedAttributes->{"doc"};
374 push(@lines, "<pre style='background: lightGrey; padding: 10px'>");
376 push(@lines, " seq: <number>,");
377 push(@lines, " type: \"event\",");
378 push(@lines, " domain: \"$domain\",");
379 if (scalar(@argsFiltered)) {
380 push(@lines, " event: \"${functionName}\",");
381 push(@lines, " data: {");
383 foreach my $parameter (@argsFiltered) {
384 push(@parameters, " " . parameterDocLine($parameter));
386 push(@lines, join(",\n", @parameters));
389 push(@lines, " event: \"${functionName}\"");
392 push(@lines, "</pre>");
393 push(@documentationLines, @lines);
399 $value =~ s/\b(\w)/\U$1/g; # make a camel-case name for type name
404 sub generateBackendFunction
406 my $interface = shift;
407 my $function = shift;
409 my $functionName = $function->signature->name;
410 my $fullQualifiedFunctionName = $interface->name . "_" . $function->signature->name;
412 push(@backendConstantDeclarations, " static const char* ${fullQualifiedFunctionName}Cmd;");
413 push(@backendConstantDefinitions, "const char* ${backendClassName}::${fullQualifiedFunctionName}Cmd = \"${functionName}\";");
415 map($backendTypes{$_->type} = 1, @{$function->parameters}); # register required types
416 my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters});
417 my @outArgs = grep($_->direction eq "out", @{$function->parameters});
419 my $signature = " void ${fullQualifiedFunctionName}(long callId, InspectorObject* requestMessageObject);";
420 !$backendMethodSignatures{${signature}} || die "Duplicate function was detected for signature '$signature'.";
421 $backendMethodSignatures{${signature}} = "$fullQualifiedFunctionName";
422 push(@backendMethods, ${signature});
425 my $requestMessageObject = scalar(@inArgs) ? " requestMessageObject" : "";
426 push(@function, "void ${backendClassName}::${fullQualifiedFunctionName}(long callId, InspectorObject*$requestMessageObject)");
427 push(@function, "{");
428 push(@function, " RefPtr<InspectorArray> protocolErrors = InspectorArray::create();");
431 my $domain = $interface->name;
432 my $domainAccessor = typeTraits($domain, "domainAccessor");
433 $backendTypes{$domain} = 1;
434 push(@function, " if (!$domainAccessor)");
435 push(@function, " protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");");
438 # declare local variables for out arguments.
439 push(@function, map(" " . typeTraits($_->type, "variable") . " " . $_->name . " = " . typeTraits($_->type, "defaultValue") . ";", @outArgs));
442 if (scalar(@inArgs)) {
443 push(@function, " if (RefPtr<InspectorObject> argumentsContainer = requestMessageObject->getObject(\"arguments\")) {");
445 foreach my $parameter (@inArgs) {
446 my $name = $parameter->name;
447 my $type = $parameter->type;
448 my $typeString = camelCase($parameter->type);
449 push(@function, " " . typeTraits($type, "variable") . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());");
455 my $args = join(", ", (map($_->name, @inArgs), map("&" . $_->name, @outArgs)));
456 push(@function, "$indent if (!protocolErrors->length())");
457 push(@function, "$indent $domainAccessor->$functionName($args);");
458 if (scalar(@inArgs)) {
459 push(@function, " } else {");
460 push(@function, " protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");");
461 push(@function, " }");
464 push(@function, " // use InspectorFrontend as a marker of WebInspector availability");
465 push(@function, " if ((callId || protocolErrors->length()) && m_inspectorAgent->hasFrontend()) {");
466 push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();");
467 push(@function, " responseMessage->setNumber(\"seq\", callId);");
468 push(@function, " responseMessage->setString(\"domain\", \"$domain\");");
469 push(@function, " responseMessage->setBoolean(\"success\", !protocolErrors->length());");
471 push(@function, " if (protocolErrors->length())");
472 push(@function, " responseMessage->setArray(\"errors\", protocolErrors);");
473 if (scalar(@outArgs)) {
474 push(@function, " else {");
475 push(@function, " RefPtr<InspectorObject> responseData = InspectorObject::create();");
476 push(@function, map(" responseData->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs));
477 push(@function, " responseMessage->setObject(\"data\", responseData);");
478 push(@function, " }");
480 push(@function, " m_inspectorAgent->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());");
481 push(@function, " }");
484 push(@function, "}");
486 push(@backendMethodsImpl, @function);
489 sub generateDocumentationCommand
491 my $interface = shift;
492 my $function = shift;
494 my $functionName = $function->signature->name;
495 my $domain = $interface->name;
499 push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>");
500 my $doc = $function->signature->extendedAttributes->{"doc"};
505 my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters});
506 push(@lines, "<pre style='background: lightGrey; padding: 10px'>");
507 push(@lines, "request: {");
508 push(@lines, " seq: <number>,");
509 push(@lines, " type: \"request\",");
510 push(@lines, " domain: \"" . $interface->name . "\",");
511 if (scalar(@inArgs)) {
512 push(@lines, " command: \"${functionName}\",");
513 push(@lines, " arguments: {");
515 foreach my $parameter (@inArgs) {
516 push(@parameters, " " . parameterDocLine($parameter));
518 push(@lines, join(",\n", @parameters));
521 push(@lines, " command: \"${functionName}\"");
525 my @outArgs = grep($_->direction eq "out", @{$function->parameters});
527 push(@lines, "response: {");
528 push(@lines, " seq: <number>,");
529 if (scalar(@outArgs)) {
530 push(@lines, " type: \"response\",");
531 push(@lines, " body: {");
533 foreach my $parameter (@outArgs) {
534 push(@parameters, " " . parameterDocLine($parameter));
536 push(@lines, join(",\n", @parameters));
539 push(@lines, " type: \"response\"");
542 push(@lines, "</pre>");
544 push(@documentationLines, @lines);
547 sub generateBackendReportProtocolError
549 my $reportProtocolError = << "EOF";
551 void ${backendClassName}::reportProtocolError(const long callId, const String& errorText) const
553 RefPtr<InspectorObject> message = InspectorObject::create();
554 message->setNumber("seq", callId);
555 message->setBoolean("success", false);
556 RefPtr<InspectorArray> errors = InspectorArray::create();
557 errors->pushString(errorText);
558 message->setArray("errors", errors);
559 m_inspectorAgent->inspectorClient()->sendMessageToFrontend(message->toJSONString());
562 return split("\n", $reportProtocolError);
565 sub generateArgumentGetters
568 my $json = typeTraits($type, "JSONType");
569 my $variable = typeTraits($type, "variable");
570 my $defaultValue = typeTraits($type, "defaultValue");
571 my $return = typeTraits($type, "return") ? typeTraits($type, "return") : typeTraits($type, "param");
573 my $typeString = camelCase($type);
574 push(@backendConstantDeclarations, " $return get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors);");
575 my $getterBody = << "EOF";
577 $return InspectorBackendDispatcher::get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors)
580 ASSERT(protocolErrors);
582 $variable value = $defaultValue;
583 InspectorObject::const_iterator end = object->end();
584 InspectorObject::const_iterator valueIterator = object->find(name);
586 if (valueIterator == end)
587 protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' with type '$json' was not found.", name.utf8().data()));
589 if (!valueIterator->second->as$json(&value))
590 protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' has wrong type. It should be '$json'.", name.utf8().data()));
596 return split("\n", $getterBody);
599 sub generateBackendDispatcher
602 my @mapEntries = map(" dispatchMap.add(${_}Cmd, &${backendClassName}::$_);", map ($backendMethodSignatures{$_}, @backendMethods));
603 my $mapEntries = join("\n", @mapEntries);
605 my $backendDispatcherBody = << "EOF";
606 void ${backendClassName}::dispatch(const String& message)
608 typedef void (${backendClassName}::*CallHandler)(long callId, InspectorObject* messageObject);
609 typedef HashMap<String, CallHandler> DispatchMap;
610 DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
613 if (dispatchMap.isEmpty()) {
617 RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
618 if (!parsedMessage) {
619 reportProtocolError(callId, "Protocol Error: Invalid message format. Message should be in JSON format.");
623 RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
624 if (!messageObject) {
625 reportProtocolError(callId, "Protocol Error: Invalid message format. The message should be a JSONified object.");
629 RefPtr<InspectorValue> commandValue = messageObject->get("command");
631 reportProtocolError(callId, "Protocol Error: Invalid message format. 'command' property wasn't found.");
636 if (!commandValue->asString(&command)) {
637 reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'command' property should be string.");
641 RefPtr<InspectorValue> callIdValue = messageObject->get("seq");
643 reportProtocolError(callId, "Protocol Error: Invalid message format. 'seq' property was not found in the request.");
647 if (!callIdValue->asNumber(&callId)) {
648 reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'seq' property should be number.");
652 HashMap<String, CallHandler>::iterator it = dispatchMap.find(command);
653 if (it == dispatchMap.end()) {
654 reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found."));
658 ((*this).*it->second)(callId, messageObject.get());
661 return split("\n", $backendDispatcherBody);
664 sub generateBackendMessageParser
666 my $messageParserBody = << "EOF";
667 bool ${backendClassName}::getCommandName(const String& message, String* result)
669 RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
673 RefPtr<InspectorObject> object = value->asObject();
677 RefPtr<InspectorValue> commandValue = object->get("command");
681 return commandValue->asString(result);
684 return split("\n", $messageParserBody);
687 sub collectBackendJSStubFunctions
689 my $interface = shift;
690 my @functions = grep(!$_->signature->extendedAttributes->{"notify"}, @{$interface->functions});
691 my $domain = $interface->name;
693 foreach my $function (@functions) {
694 my $name = $function->signature->name;
695 my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . typeTraits($_->type, "JSType") . "\"", grep($_->direction eq "in", @{$function->parameters})));
696 push(@backendJSStubs, " this._registerDelegate('{" .
698 "\"domain\": \"$domain\", " .
699 "\"command\": \"$name\", " .
700 "\"arguments\": {$argumentNames}" .
705 sub generateBackendStubJS
707 my $JSStubs = join("\n", @backendJSStubs);
708 my $inspectorBackendStubJS = << "EOF";
711 InspectorBackendStub = function()
713 this._lastCallbackId = 1;
714 this._callbacks = {};
715 this._domainDispatchers = {};
719 InspectorBackendStub.prototype = {
720 _wrap: function(callback)
722 var callbackId = this._lastCallbackId++;
723 this._callbacks[callbackId] = callback || function() {};
727 _processResponse: function(callbackId, args)
729 var callback = this._callbacks[callbackId];
730 callback.apply(null, args);
731 delete this._callbacks[callbackId];
734 _removeResponseCallbackEntry: function(callbackId)
736 delete this._callbacks[callbackId];
739 _registerDelegate: function(commandInfo)
741 var commandObject = JSON.parse(commandInfo);
742 var agentName = commandObject.domain + "Agent";
743 if (!window[agentName])
744 window[agentName] = {};
745 window[agentName][commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo);
748 sendMessageToBackend: function()
750 var args = Array.prototype.slice.call(arguments);
751 var request = JSON.parse(args.shift());
753 for (var key in request.arguments) {
754 if (args.length === 0) {
755 console.error("Protocol Error: Invalid number of arguments for '%sAgent.%s' call. It should have the next arguments '%s'.", request.domain, request.command, JSON.stringify(request.arguments));
758 var value = args.shift();
759 if (request.arguments[key] && typeof value !== request.arguments[key]) {
760 console.error("Protocol Error: Invalid type of argument '%s' for '%sAgent.%s' call. It should be '%s' but it is '%s'.", key, request.domain, request.command, request.arguments[key], typeof value);
763 request.arguments[key] = value;
766 if (args.length === 1) {
767 if (typeof args[0] !== "function" && typeof args[0] !== "undefined") {
768 console.error("Protocol Error: Optional callback argument for '%sAgent.%s' call should be a function but its type is '%s'.", request.domain, request.command, typeof args[0]);
771 request.seq = this._wrap(args[0]);
774 if (window.dumpInspectorProtocolMessages)
775 console.log("frontend: " + JSON.stringify(request));
777 var message = JSON.stringify(request);
778 InspectorFrontendHost.sendMessageToBackend(message);
781 registerDomainDispatcher: function(domain, dispatcher)
783 this._domainDispatchers[domain] = dispatcher;
786 dispatch: function(message)
788 if (window.dumpInspectorProtocolMessages)
789 console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message)));
791 var messageObject = (typeof message === "string") ? JSON.parse(message) : message;
794 if (messageObject.data)
795 for (var key in messageObject.data)
796 arguments.push(messageObject.data[key]);
798 if ("seq" in messageObject) { // just a response for some request
799 if (messageObject.success)
800 this._processResponse(messageObject.seq, arguments);
802 this._removeResponseCallbackEntry(messageObject.seq)
803 this.reportProtocolError(messageObject);
808 if (messageObject.type === "event") {
809 if (!(messageObject.domain in this._domainDispatchers)) {
810 console.error("Protocol Error: the message is for non-existing domain '%s'", messageObject.domain);
813 var dispatcher = this._domainDispatchers[messageObject.domain];
814 if (!(messageObject.event in dispatcher)) {
815 console.error("Protocol Error: Attempted to dispatch an unimplemented method '%s.%s'", messageObject.domain, messageObject.event);
818 dispatcher[messageObject.event].apply(dispatcher, arguments);
822 reportProtocolError: function(messageObject)
824 console.error("Protocol Error: InspectorBackend request with seq = %d failed.", messageObject.seq);
825 for (var i = 0; i < messageObject.errors.length; ++i)
826 console.error(" " + messageObject.errors[i]);
827 this._removeResponseCallbackEntry(messageObject.seq);
831 InspectorBackend = new InspectorBackendStub();
834 return split("\n", $inspectorBackendStubJS);
839 my $className = shift;
841 my $constructor = shift;
842 my $constants = shift;
846 my $forwardHeaders = join("\n", sort(map("#include <" . typeTraits($_, "forwardHeader") . ">", grep(typeTraits($_, "forwardHeader"), keys %{$types}))));
847 my $forwardDeclarations = join("\n", sort(map("class " . typeTraits($_, "forward") . ";", grep(typeTraits($_, "forward"), keys %{$types}))));
848 my $constantDeclarations = join("\n", @{$constants});
849 my $methodsDeclarations = join("\n", @{$methods});
851 my $headerBody = << "EOF";
852 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
853 // Use of this source code is governed by a BSD-style license that can be
854 // found in the LICENSE file.
855 #ifndef ${className}_h
856 #define ${className}_h
860 namespace $namespace {
868 $constantDeclarations
874 } // namespace $namespace
875 #endif // !defined(${className}_h)
883 my $className = shift;
885 my $constants = shift;
888 my @sourceContent = split("\r", $licenseTemplate);
889 push(@sourceContent, "\n#include \"config.h\"");
890 push(@sourceContent, "#include \"$className.h\"");
891 push(@sourceContent, "#include <wtf/text/StringConcatenate.h>");
892 push(@sourceContent, "#include <wtf/text/CString.h>");
893 push(@sourceContent, "");
894 push(@sourceContent, "#if ENABLE(INSPECTOR)");
895 push(@sourceContent, "");
898 foreach my $type (keys %{$types}) {
899 $headers{"#include \"" . typeTraits($type, "header") . "\""} = 1 if !typeTraits($type, "header") eq "";
901 push(@sourceContent, sort keys %headers);
902 push(@sourceContent, "");
903 push(@sourceContent, "namespace $namespace {");
904 push(@sourceContent, "");
905 push(@sourceContent, join("\n", @{$constants}));
906 push(@sourceContent, "");
907 push(@sourceContent, @{$methods});
908 push(@sourceContent, "");
909 push(@sourceContent, "} // namespace $namespace");
910 push(@sourceContent, "");
911 push(@sourceContent, "#endif // ENABLE(INSPECTOR)");
912 push(@sourceContent, "");
913 return @sourceContent;
920 return $typeTransform{$type}->{$trait};
925 my $parameter = shift;
926 my $subtype = $parameter->extendedAttributes->{"type"};
928 my $pattern = typeTraits($parameter->type, "DocType");
929 return sprintf($pattern, "<$subtype>");
932 my $subtypeRef = $parameter->extendedAttributes->{"typeRef"};
934 my $pattern = typeTraits($parameter->type, "DocType");
935 return sprintf($pattern, "<<a href='#$subtypeRef'>" . $subtypeRef . "</a>>");
938 return "<" . typeTraits($parameter->type, "JSType") . ">";
943 my $parameter = shift;
945 my $result = $parameter->name . ": " . parameterDocType($parameter);
946 my $doc = $parameter->extendedAttributes->{"doc"};
948 $result = $result . " // " . $doc;
957 push(@backendMethodsImpl, generateBackendDispatcher());
958 push(@backendMethodsImpl, generateBackendReportProtocolError());
960 open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp";
961 print $SOURCE join("\n", generateSource($frontendClassName, \%frontendTypes, \@frontendConstantDefinitions, \@frontendMethodsImpl));
965 open(my $HEADER, ">$outputHeadersDir/$frontendClassName.h") || die "Couldn't open file $outputHeadersDir/$frontendClassName.h";
966 print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \@frontendConstantDeclarations, \@frontendMethods, $frontendFooter);
970 # Make dispatcher methods private on the backend.
971 push(@backendConstantDeclarations, "");
972 push(@backendConstantDeclarations, "private:");
974 foreach my $type (keys %backendTypes) {
975 if (typeTraits($type, "JSONType")) {
976 push(@backendMethodsImpl, generateArgumentGetters($type));
980 push(@backendMethodsImpl, generateBackendMessageParser());
981 push(@backendMethodsImpl, "");
983 push(@backendConstantDeclarations, "");
985 open($SOURCE, ">$outputDir/$backendClassName.cpp") || die "Couldn't open file $outputDir/$backendClassName.cpp";
986 print $SOURCE join("\n", generateSource($backendClassName, \%backendTypes, \@backendConstantDefinitions, \@backendMethodsImpl));
990 open($HEADER, ">$outputHeadersDir/$backendClassName.h") || die "Couldn't open file $outputHeadersDir/$backendClassName.h";
991 print $HEADER join("\n", generateHeader($backendClassName, \%backendTypes, $backendConstructor, \@backendConstantDeclarations, \@backendMethods, $backendFooter));
995 open(my $JS_STUB, ">$outputDir/$backendJSStubName.js") || die "Couldn't open file $outputDir/$backendJSStubName.js";
996 print $JS_STUB join("\n", generateBackendStubJS());
1000 open(my $DOCS, ">$outputDir/WebInspectorProtocol.html") || die "Couldn't open file $outputDir/WebInspectorProtocol.html";
1001 print $DOCS "<ol class='toc' style='list-style: none; padding: 0'>";
1002 print $DOCS join("\n", @documentationToc);
1003 print $DOCS "</ol>";
1004 print $DOCS join("\n", @documentationLines);