summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/inspector/CodeGeneratorInspector.pm
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/inspector/CodeGeneratorInspector.pm
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/inspector/CodeGeneratorInspector.pm')
-rw-r--r--Source/WebCore/inspector/CodeGeneratorInspector.pm806
1 files changed, 806 insertions, 0 deletions
diff --git a/Source/WebCore/inspector/CodeGeneratorInspector.pm b/Source/WebCore/inspector/CodeGeneratorInspector.pm
new file mode 100644
index 0000000..b8aea0e
--- /dev/null
+++ b/Source/WebCore/inspector/CodeGeneratorInspector.pm
@@ -0,0 +1,806 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+package CodeGeneratorInspector;
+
+use strict;
+
+use Class::Struct;
+use File::stat;
+
+my %typeTransform;
+$typeTransform{"ApplicationCache"} = {
+ "forward" => "InspectorApplicationCacheAgent",
+ "header" => "InspectorApplicationCacheAgent.h",
+ "domainAccessor" => "m_inspectorController->m_applicationCacheAgent",
+};
+$typeTransform{"CSS"} = {
+ "forward" => "InspectorCSSAgent",
+ "header" => "InspectorCSSAgent.h",
+ "domainAccessor" => "m_inspectorController->m_cssAgent",
+};
+$typeTransform{"Debugger"} = {
+ "forward" => "InspectorDebuggerAgent",
+ "header" => "InspectorDebuggerAgent.h",
+ "domainAccessor" => "m_inspectorController->m_debuggerAgent",
+};
+$typeTransform{"Database"} = {
+ "forward" => "InspectorDatabaseAgent",
+ "header" => "InspectorDatabaseAgent.h",
+ "domainAccessor" => "m_inspectorController->m_databaseAgent",
+};
+$typeTransform{"DOM"} = {
+ "forward" => "InspectorDOMAgent",
+ "header" => "InspectorDOMAgent.h",
+ "domainAccessor" => "m_inspectorController->m_domAgent",
+};
+$typeTransform{"DOMStorage"} = {
+ "forward" => "InspectorDOMStorageAgent",
+ "header" => "InspectorDOMStorageAgent.h",
+ "domainAccessor" => "m_inspectorController->m_domStorageAgent",
+};
+$typeTransform{"FileSystem"} = {
+ "forward" => "InspectorFileSystemAgent",
+ "header" => "InspectorFileSystemAgent.h",
+ "domainAccessor" => "m_inspectorController->m_fileSystemAgent",
+};
+$typeTransform{"Inspector"} = {
+ "forwardHeader" => "InspectorController.h",
+ "domainAccessor" => "m_inspectorController",
+};
+$typeTransform{"Network"} = {
+ "forward" => "InspectorResourceAgent",
+ "header" => "InspectorResourceAgent.h",
+ "domainAccessor" => "m_inspectorController->m_resourceAgent",
+};
+$typeTransform{"Profiler"} = {
+ "forward" => "InspectorProfilerAgent",
+ "header" => "InspectorProfilerAgent.h",
+ "domainAccessor" => "m_inspectorController->m_profilerAgent",
+};
+
+$typeTransform{"Frontend"} = {
+ "forward" => "InspectorFrontend",
+ "header" => "InspectorFrontend.h",
+};
+$typeTransform{"InspectorClient"} = {
+ "forward" => "InspectorClient",
+ "header" => "InspectorClient.h",
+};
+$typeTransform{"PassRefPtr"} = {
+ "forwardHeader" => "wtf/PassRefPtr.h",
+};
+$typeTransform{"Object"} = {
+ "param" => "PassRefPtr<InspectorObject>",
+ "variable" => "RefPtr<InspectorObject>",
+ "defaultValue" => "InspectorObject::create()",
+ "forward" => "InspectorObject",
+ "header" => "InspectorValues.h",
+ "JSONType" => "Object"
+};
+$typeTransform{"Array"} = {
+ "param" => "PassRefPtr<InspectorArray>",
+ "variable" => "RefPtr<InspectorArray>",
+ "defaultValue" => "InspectorArray::create()",
+ "forward" => "InspectorArray",
+ "header" => "InspectorValues.h",
+ "JSONType" => "Array"
+};
+$typeTransform{"Value"} = {
+ "param" => "PassRefPtr<InspectorValue>",
+ "variable" => "RefPtr<InspectorValue>",
+ "defaultValue" => "InspectorValue::null()",
+ "forward" => "InspectorValue",
+ "header" => "InspectorValues.h",
+ "JSONType" => "Value"
+};
+$typeTransform{"String"} = {
+ "param" => "const String&",
+ "variable" => "String",
+ "return" => "String",
+ "defaultValue" => "\"\"",
+ "forwardHeader" => "wtf/Forward.h",
+ "header" => "PlatformString.h",
+ "JSONType" => "String"
+};
+$typeTransform{"long"} = {
+ "param" => "long",
+ "variable" => "long",
+ "defaultValue" => "0",
+ "forward" => "",
+ "header" => "",
+ "JSONType" => "Number"
+};
+$typeTransform{"int"} = {
+ "param" => "int",
+ "variable" => "int",
+ "defaultValue" => "0",
+ "forward" => "",
+ "header" => "",
+ "JSONType" => "Number",
+};
+$typeTransform{"unsigned long"} = {
+ "param" => "unsigned long",
+ "variable" => "unsigned long",
+ "defaultValue" => "0u",
+ "forward" => "",
+ "header" => "",
+ "JSONType" => "Number"
+};
+$typeTransform{"unsigned int"} = {
+ "param" => "unsigned int",
+ "variable" => "unsigned int",
+ "defaultValue" => "0u",
+ "forward" => "",
+ "header" => "",
+ "JSONType" => "Number"
+};
+$typeTransform{"double"} = {
+ "param" => "double",
+ "variable" => "double",
+ "defaultValue" => "0.0",
+ "forward" => "",
+ "header" => "",
+ "JSONType" => "Number"
+};
+$typeTransform{"boolean"} = {
+ "param" => "bool",
+ "variable"=> "bool",
+ "defaultValue" => "false",
+ "forward" => "",
+ "header" => "",
+ "JSONType" => "Boolean"
+};
+$typeTransform{"void"} = {
+ "forward" => "",
+ "header" => ""
+};
+
+# Default License Templates
+
+my $licenseTemplate = << "EOF";
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+EOF
+
+my $codeGenerator;
+my $outputDir;
+my $outputHeadersDir;
+my $writeDependencies;
+my $verbose;
+
+my $namespace;
+
+my $backendClassName;
+my $backendJSStubName;
+my %backendTypes;
+my %backendMethods;
+my @backendMethodsImpl;
+my $backendConstructor;
+my @backendConstantDeclarations;
+my @backendConstantDefinitions;
+my $backendFooter;
+my @backendStubJS;
+
+my $frontendClassName;
+my %frontendTypes;
+my %frontendMethods;
+my @frontendMethodsImpl;
+my $frontendConstructor;
+my @frontendConstantDeclarations;
+my @frontendConstantDefinitions;
+my $frontendFooter;
+
+# Default constructor
+sub new
+{
+ my $object = shift;
+ my $reference = { };
+
+ $codeGenerator = shift;
+ $outputDir = shift;
+ $outputHeadersDir = shift;
+ shift; # $useLayerOnTop
+ shift; # $preprocessor
+ $writeDependencies = shift;
+ $verbose = shift;
+
+ bless($reference, $object);
+ return $reference;
+}
+
+# Params: 'idlDocument' struct
+sub GenerateModule
+{
+ my $object = shift;
+ my $dataNode = shift;
+
+ $namespace = $dataNode->module;
+ $namespace =~ s/core/WebCore/;
+}
+
+# Params: 'idlDocument' struct
+sub GenerateInterface
+{
+ my $object = shift;
+ my $interface = shift;
+ my $defines = shift;
+
+ my $className = $interface->name;
+
+ $frontendClassName = $className . "Frontend";
+ $frontendConstructor = " ${frontendClassName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }";
+ $frontendFooter = " InspectorClient* m_inspectorClient;";
+ $frontendTypes{"String"} = 1;
+ $frontendTypes{"InspectorClient"} = 1;
+ $frontendTypes{"PassRefPtr"} = 1;
+
+ $backendClassName = $className . "BackendDispatcher";
+ $backendJSStubName = $className . "BackendStub";
+ my @backendHead;
+ push(@backendHead, " ${backendClassName}(InspectorController* inspectorController) : m_inspectorController(inspectorController) { }");
+ push(@backendHead, " void reportProtocolError(const long callId, const String& errorText) const;");
+ push(@backendHead, " void dispatch(const String& message);");
+ push(@backendHead, " static bool getCommandName(const String& message, String* result);");
+ $backendConstructor = join("\n", @backendHead);
+ $backendFooter = " InspectorController* m_inspectorController;";
+ $backendTypes{"Inspector"} = 1;
+ $backendTypes{"InspectorClient"} = 1;
+ $backendTypes{"PassRefPtr"} = 1;
+ $backendTypes{"Object"} = 1;
+
+ push(@backendMethodsImpl, generateBackendMessageParser());
+ generateFunctions($interface);
+
+ # Make dispatcher methods private on the backend.
+ push(@backendConstantDeclarations, "");
+ push(@backendConstantDeclarations, "private:");
+}
+
+sub generateFunctions
+{
+ my $interface = shift;
+
+ foreach my $function (@{$interface->functions}) {
+ if ($function->signature->extendedAttributes->{"notify"}) {
+ generateFrontendFunction($function);
+ } else {
+ generateBackendFunction($function);
+ }
+ }
+ push(@backendMethodsImpl, generateBackendDispatcher());
+ push(@backendMethodsImpl, generateBackendReportProtocolError());
+
+ foreach my $type (keys %backendTypes) {
+ if ($typeTransform{$type}{"JSONType"}) {
+ push(@backendMethodsImpl, generateArgumentGetters($type));
+ }
+ }
+
+ @backendStubJS = generateBackendStubJS($interface);
+}
+
+sub generateFrontendFunction
+{
+ my $function = shift;
+
+ my $functionName = $function->signature->name;
+
+ my $domain = $function->signature->extendedAttributes->{"domain"} || "Inspector";
+ my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); # just keep only out parameters for frontend interface.
+ map($frontendTypes{$_->type} = 1, @argsFiltered); # register required types.
+ my $arguments = join(", ", map($typeTransform{$_->type}->{"param"} . " " . $_->name, @argsFiltered)); # prepare arguments for function signature.
+
+ my $signature = " void ${functionName}(${arguments});";
+ if (!$frontendMethods{${signature}}) {
+ $frontendMethods{${signature}} = 1;
+
+ my @function;
+ push(@function, "void ${frontendClassName}::${functionName}(${arguments})");
+ push(@function, "{");
+ push(@function, " RefPtr<InspectorObject> ${functionName}Message = InspectorObject::create();");
+ push(@function, " ${functionName}Message->setString(\"type\", \"event\");");
+ push(@function, " ${functionName}Message->setString(\"domain\", \"$domain\");");
+ push(@function, " ${functionName}Message->setString(\"event\", \"$functionName\");");
+ push(@function, " RefPtr<InspectorObject> payloadDataObject = InspectorObject::create();");
+ my @pushArguments = map(" payloadDataObject->set" . $typeTransform{$_->type}->{"JSONType"} . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered);
+ push(@function, @pushArguments);
+ push(@function, " ${functionName}Message->setObject(\"data\", payloadDataObject);");
+ push(@function, " m_inspectorClient->sendMessageToFrontend(${functionName}Message->toJSONString());");
+
+ push(@function, "}");
+ push(@function, "");
+ push(@frontendMethodsImpl, @function);
+ }
+}
+
+sub camelCase
+{
+ my $value = shift;
+ $value =~ s/\b(\w)/\U$1/g; # make a camel-case name for type name
+ $value =~ s/ //g;
+ return $value;
+}
+
+sub generateBackendFunction
+{
+ my $function = shift;
+
+ my $functionName = $function->signature->name;
+
+ push(@backendConstantDeclarations, " static const char* ${functionName}Cmd;");
+ push(@backendConstantDefinitions, "const char* ${backendClassName}::${functionName}Cmd = \"${functionName}\";");
+
+ map($backendTypes{$_->type} = 1, @{$function->parameters}); # register required types
+ my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters});
+ my @outArgs = grep($_->direction eq "out", @{$function->parameters});
+
+ my $signature = " void ${functionName}(long callId, InspectorObject* requestMessageObject);";
+ !$backendMethods{${signature}} || die "Duplicate function was detected for signature '$signature'.";
+ $backendMethods{${signature}} = $functionName;
+
+ my @function;
+ my $requestMessageObject = scalar(@inArgs) ? " requestMessageObject" : "";
+ push(@function, "void ${backendClassName}::${functionName}(long callId, InspectorObject*$requestMessageObject)");
+ push(@function, "{");
+ push(@function, " RefPtr<InspectorArray> protocolErrors = InspectorArray::create();");
+ push(@function, "");
+
+ my $domain = $function->signature->extendedAttributes->{"domain"} || "Inspector";
+ my $domainAccessor = $typeTransform{$domain}->{"domainAccessor"};
+ $backendTypes{$domain} = 1;
+ push(@function, " if (!$domainAccessor)");
+ push(@function, " protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");");
+ push(@function, "");
+
+ # declare local variables for out arguments.
+ push(@function, map(" " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @outArgs));
+
+ my $indent = "";
+ if (scalar(@inArgs)) {
+ push(@function, " if (RefPtr<InspectorObject> argumentsContainer = requestMessageObject->getObject(\"arguments\")) {");
+
+ foreach my $parameter (@inArgs) {
+ my $name = $parameter->name;
+ my $type = $parameter->type;
+ my $typeString = camelCase($parameter->type);
+ push(@function, " " . $typeTransform{$type}->{"variable"} . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());");
+ }
+ push(@function, "");
+ $indent = " ";
+ }
+
+ my $args = join(", ", (map($_->name, @inArgs), map("&" . $_->name, @outArgs)));
+ push(@function, "$indent if (!protocolErrors->length())");
+ push(@function, "$indent $domainAccessor->$functionName($args);");
+ if (scalar(@inArgs)) {
+ push(@function, " } else {");
+ push(@function, " protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");");
+ push(@function, " }");
+ }
+
+ push(@function, " // use InspectorFrontend as a marker of WebInspector availability");
+ push(@function, " if ((callId || protocolErrors->length()) && m_inspectorController->hasFrontend()) {");
+ push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();");
+ push(@function, " responseMessage->setNumber(\"seq\", callId);");
+ push(@function, " responseMessage->setString(\"domain\", \"$domain\");");
+ push(@function, " responseMessage->setBoolean(\"success\", !protocolErrors->length());");
+ push(@function, "");
+ push(@function, " if (protocolErrors->length())");
+ push(@function, " responseMessage->setArray(\"errors\", protocolErrors);");
+ if (scalar(@outArgs)) {
+ push(@function, " else {");
+ push(@function, " RefPtr<InspectorObject> responseData = InspectorObject::create();");
+ push(@function, map(" responseData->set" . $typeTransform{$_->type}->{"JSONType"} . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs));
+ push(@function, " responseMessage->setObject(\"data\", responseData);");
+ push(@function, " }");
+ }
+ push(@function, " m_inspectorController->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());");
+ push(@function, " }");
+
+
+ push(@function, "}");
+ push(@function, "");
+ push(@backendMethodsImpl, @function);
+}
+
+sub generateBackendReportProtocolError
+{
+ my $reportProtocolError = << "EOF";
+
+void ${backendClassName}::reportProtocolError(const long callId, const String& errorText) const
+{
+ RefPtr<InspectorObject> message = InspectorObject::create();
+ message->setNumber("seq", callId);
+ message->setBoolean("success", false);
+ RefPtr<InspectorArray> errors = InspectorArray::create();
+ errors->pushString(errorText);
+ message->setArray("errors", errors);
+ m_inspectorController->inspectorClient()->sendMessageToFrontend(message->toJSONString());
+}
+EOF
+ return split("\n", $reportProtocolError);
+}
+
+sub generateArgumentGetters
+{
+ my $type = shift;
+ my $json = $typeTransform{$type}{"JSONType"};
+ my $variable = $typeTransform{$type}{"variable"};
+ my $defaultValue = $typeTransform{$type}{"defaultValue"};
+ my $return = $typeTransform{$type}{"return"} ? $typeTransform{$type}{"return"} : $typeTransform{$type}{"param"};
+
+ my $typeString = camelCase($type);
+ push(@backendConstantDeclarations, "$return get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors);");
+ my $getterBody = << "EOF";
+
+$return InspectorBackendDispatcher::get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors)
+{
+ ASSERT(object);
+ ASSERT(protocolErrors);
+
+ $variable value = $defaultValue;
+ InspectorObject::const_iterator end = object->end();
+ InspectorObject::const_iterator valueIterator = object->find(name);
+
+ if (valueIterator == end)
+ protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' with type '$json' was not found.", name.utf8().data()));
+ else {
+ if (!valueIterator->second->as$json(&value))
+ protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' has wrong type. It should be '$json'.", name.utf8().data()));
+ }
+ return value;
+}
+EOF
+
+ return split("\n", $getterBody);
+}
+
+sub generateBackendDispatcher
+{
+ my @body;
+ my @methods = map($backendMethods{$_}, keys %backendMethods);
+ my @mapEntries = map(" dispatchMap.add(${_}Cmd, &${backendClassName}::$_);", @methods);
+ my $mapEntries = join("\n", @mapEntries);
+
+ my $backendDispatcherBody = << "EOF";
+void ${backendClassName}::dispatch(const String& message)
+{
+ typedef void (${backendClassName}::*CallHandler)(long callId, InspectorObject* messageObject);
+ typedef HashMap<String, CallHandler> DispatchMap;
+ DEFINE_STATIC_LOCAL(DispatchMap, dispatchMap, );
+ long callId = 0;
+
+ if (dispatchMap.isEmpty()) {
+$mapEntries
+ }
+
+ RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message);
+ if (!parsedMessage) {
+ reportProtocolError(callId, "Protocol Error: Invalid message format. Message should be in JSON format.");
+ return;
+ }
+
+ RefPtr<InspectorObject> messageObject = parsedMessage->asObject();
+ if (!messageObject) {
+ reportProtocolError(callId, "Protocol Error: Invalid message format. The message should be a JSONified object.");
+ return;
+ }
+
+ RefPtr<InspectorValue> commandValue = messageObject->get("command");
+ if (!commandValue) {
+ reportProtocolError(callId, "Protocol Error: Invalid message format. 'command' property wasn't found.");
+ return;
+ }
+
+ String command;
+ if (!commandValue->asString(&command)) {
+ reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'command' property should be string.");
+ return;
+ }
+
+ RefPtr<InspectorValue> callIdValue = messageObject->get("seq");
+ if (!callIdValue) {
+ reportProtocolError(callId, "Protocol Error: Invalid message format. 'seq' property was not found in the request.");
+ return;
+ }
+
+ if (!callIdValue->asNumber(&callId)) {
+ reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'seq' property should be number.");
+ return;
+ }
+
+ HashMap<String, CallHandler>::iterator it = dispatchMap.find(command);
+ if (it == dispatchMap.end()) {
+ reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found."));
+ return;
+ }
+
+ ((*this).*it->second)(callId, messageObject.get());
+}
+EOF
+ return split("\n", $backendDispatcherBody);
+}
+
+sub generateBackendMessageParser
+{
+ my $messageParserBody = << "EOF";
+bool ${backendClassName}::getCommandName(const String& message, String* result)
+{
+ RefPtr<InspectorValue> value = InspectorValue::parseJSON(message);
+ if (!value)
+ return false;
+
+ RefPtr<InspectorObject> object = value->asObject();
+ if (!object)
+ return false;
+
+ RefPtr<InspectorValue> commandValue = object->get("command");
+ if (!commandValue)
+ return false;
+
+ return commandValue->asString(result);
+}
+
+EOF
+ return split("\n", $messageParserBody);
+}
+
+sub generateBackendStubJS
+{
+ my $interface = shift;
+ my @backendFunctions = grep(!$_->signature->extendedAttributes->{"notify"}, @{$interface->functions});
+ my @JSStubs;
+
+ foreach my $function (@backendFunctions) {
+ my $name = $function->signature->name;
+ my $domain = $function->signature->extendedAttributes->{"domain"};
+ my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . lc($typeTransform{$_->type}->{"JSONType"}) . "\"", grep($_->direction eq "in", @{$function->parameters})));
+ push(@JSStubs, " this._registerDelegate('{" .
+ "\"seq\": 0, " .
+ "\"domain\": \"$domain\", " .
+ "\"command\": \"$name\", " .
+ "\"arguments\": {$argumentNames}" .
+ "}');");
+ }
+
+ my $JSStubs = join("\n", @JSStubs);
+ my $inspectorBackendStubJS = << "EOF";
+$licenseTemplate
+
+InspectorBackendStub = function()
+{
+ this._lastCallbackId = 1;
+ this._callbacks = {};
+ this._domainDispatchers = {};
+$JSStubs
+}
+
+InspectorBackendStub.prototype = {
+ _wrap: function(callback)
+ {
+ var callbackId = this._lastCallbackId++;
+ this._callbacks[callbackId] = callback || function() {};
+ return callbackId;
+ },
+
+ _processResponse: function(callbackId, args)
+ {
+ var callback = this._callbacks[callbackId];
+ callback.apply(null, args);
+ delete this._callbacks[callbackId];
+ },
+
+ _removeResponseCallbackEntry: function(callbackId)
+ {
+ delete this._callbacks[callbackId];
+ },
+
+ _registerDelegate: function(commandInfo)
+ {
+ var commandObject = JSON.parse(commandInfo);
+ this[commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo);
+ },
+
+ sendMessageToBackend: function()
+ {
+ var args = Array.prototype.slice.call(arguments);
+ var request = JSON.parse(args.shift());
+
+ for (var key in request.arguments) {
+ if (args.length === 0) {
+ 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));
+ return;
+ }
+ var value = args.shift();
+ if (typeof value !== request.arguments[key]) {
+ 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);
+ return;
+ }
+ request.arguments[key] = value;
+ }
+
+ if (args.length === 1) {
+ if (typeof args[0] !== "function" && typeof args[0] !== "undefined") {
+ 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]);
+ return;
+ }
+ request.seq = this._wrap(args[0]);
+ }
+
+ if (window.dumpInspectorProtocolMessages)
+ console.log("frontend: " + JSON.stringify(request));
+
+ var message = JSON.stringify(request);
+ InspectorFrontendHost.sendMessageToBackend(message);
+ },
+
+ registerDomainDispatcher: function(domain, dispatcher)
+ {
+ this._domainDispatchers[domain] = dispatcher;
+ },
+
+ dispatch: function(message)
+ {
+ if (window.dumpInspectorProtocolMessages)
+ console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message)));
+
+ var messageObject = (typeof message === "string") ? JSON.parse(message) : message;
+
+ var arguments = [];
+ if (messageObject.data)
+ for (var key in messageObject.data)
+ arguments.push(messageObject.data[key]);
+
+ if ("seq" in messageObject) { // just a response for some request
+ if (messageObject.success)
+ this._processResponse(messageObject.seq, arguments);
+ else {
+ this._removeResponseCallbackEntry(messageObject.seq)
+ this.reportProtocolError(messageObject);
+ }
+ return;
+ }
+
+ if (messageObject.type === "event") {
+ if (!(messageObject.domain in this._domainDispatchers)) {
+ console.error("Protocol Error: the message is for non-existing domain '%s'", messageObject.domain);
+ return;
+ }
+ var dispatcher = this._domainDispatchers[messageObject.domain];
+ if (!(messageObject.event in dispatcher)) {
+ console.error("Protocol Error: Attempted to dispatch an unimplemented method '%s.%s'", messageObject.domain, messageObject.event);
+ return;
+ }
+ dispatcher[messageObject.event].apply(dispatcher, arguments);
+ }
+ },
+
+ reportProtocolError: function(messageObject)
+ {
+ console.error("Protocol Error: InspectorBackend request with seq = %d failed.", messageObject.seq);
+ for (var i = 0; i < messageObject.errors.length; ++i)
+ console.error(" " + messageObject.errors[i]);
+ this._removeResponseCallbackEntry(messageObject.seq);
+ }
+}
+
+InspectorBackend = new InspectorBackendStub();
+
+EOF
+ return split("\n", $inspectorBackendStubJS);
+}
+
+sub generateHeader
+{
+ my $className = shift;
+ my $types = shift;
+ my $constructor = shift;
+ my $constants = shift;
+ my $methods = shift;
+ my $footer = shift;
+
+ my $forwardHeaders = join("\n", sort(map("#include <" . $typeTransform{$_}->{"forwardHeader"} . ">", grep($typeTransform{$_}->{"forwardHeader"}, keys %{$types}))));
+ my $forwardDeclarations = join("\n", sort(map("class " . $typeTransform{$_}->{"forward"} . ";", grep($typeTransform{$_}->{"forward"}, keys %{$types}))));
+ my $constantDeclarations = join("\n", @{$constants});
+ my $methodsDeclarations = join("\n", keys %{$methods});
+
+ my $headerBody = << "EOF";
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef ${className}_h
+#define ${className}_h
+
+${forwardHeaders}
+
+namespace $namespace {
+
+$forwardDeclarations
+
+class $className {
+public:
+$constructor
+
+$constantDeclarations
+$methodsDeclarations
+
+private:
+$footer
+};
+
+} // namespace $namespace
+#endif // !defined(${className}_h)
+
+EOF
+ return $headerBody;
+}
+
+sub generateSource
+{
+ my $className = shift;
+ my $types = shift;
+ my $constants = shift;
+ my $methods = shift;
+
+ my @sourceContent = split("\r", $licenseTemplate);
+ push(@sourceContent, "\n#include \"config.h\"");
+ push(@sourceContent, "#include \"$className.h\"");
+ push(@sourceContent, "#include <wtf/text/StringConcatenate.h>");
+ push(@sourceContent, "#include <wtf/text/CString.h>");
+ push(@sourceContent, "");
+ push(@sourceContent, "#if ENABLE(INSPECTOR)");
+ push(@sourceContent, "");
+
+ my %headers;
+ foreach my $type (keys %{$types}) {
+ $headers{"#include \"" . $typeTransform{$type}->{"header"} . "\""} = 1 if !$typeTransform{$type}->{"header"} eq "";
+ }
+ push(@sourceContent, sort keys %headers);
+ push(@sourceContent, "");
+ push(@sourceContent, "namespace $namespace {");
+ push(@sourceContent, "");
+ push (@sourceContent, join("\n", @{$constants}));
+ push(@sourceContent, "");
+ push(@sourceContent, @{$methods});
+ push(@sourceContent, "");
+ push(@sourceContent, "} // namespace $namespace");
+ push(@sourceContent, "");
+ push(@sourceContent, "#endif // ENABLE(INSPECTOR)");
+ push(@sourceContent, "");
+ return @sourceContent;
+}
+
+sub finish
+{
+ my $object = shift;
+
+ open(my $SOURCE, ">$outputDir/$frontendClassName.cpp") || die "Couldn't open file $outputDir/$frontendClassName.cpp";
+ print $SOURCE join("\n", generateSource($frontendClassName, \%frontendTypes, \@frontendConstantDefinitions, \@frontendMethodsImpl));
+ close($SOURCE);
+ undef($SOURCE);
+
+ open(my $HEADER, ">$outputHeadersDir/$frontendClassName.h") || die "Couldn't open file $outputHeadersDir/$frontendClassName.h";
+ print $HEADER generateHeader($frontendClassName, \%frontendTypes, $frontendConstructor, \@frontendConstantDeclarations, \%frontendMethods, $frontendFooter);
+ close($HEADER);
+ undef($HEADER);
+
+ open($SOURCE, ">$outputDir/$backendClassName.cpp") || die "Couldn't open file $outputDir/$backendClassName.cpp";
+ print $SOURCE join("\n", generateSource($backendClassName, \%backendTypes, \@backendConstantDefinitions, \@backendMethodsImpl));
+ close($SOURCE);
+ undef($SOURCE);
+
+ open($HEADER, ">$outputHeadersDir/$backendClassName.h") || die "Couldn't open file $outputHeadersDir/$backendClassName.h";
+ print $HEADER join("\n", generateHeader($backendClassName, \%backendTypes, $backendConstructor, \@backendConstantDeclarations, \%backendMethods, $backendFooter));
+ close($HEADER);
+ undef($HEADER);
+
+ open(my $JS_STUB, ">$outputDir/$backendJSStubName.js") || die "Couldn't open file $outputDir/$backendJSStubName.js";
+ print $JS_STUB join("\n", @backendStubJS);
+ close($JS_STUB);
+ undef($JS_STUB);
+}
+
+1;