diff options
Diffstat (limited to 'Source/WebCore/inspector/CodeGeneratorInspector.pm')
-rw-r--r-- | Source/WebCore/inspector/CodeGeneratorInspector.pm | 541 |
1 files changed, 235 insertions, 306 deletions
diff --git a/Source/WebCore/inspector/CodeGeneratorInspector.pm b/Source/WebCore/inspector/CodeGeneratorInspector.pm index ea65f2e..de8e1db 100644 --- a/Source/WebCore/inspector/CodeGeneratorInspector.pm +++ b/Source/WebCore/inspector/CodeGeneratorInspector.pm @@ -90,13 +90,13 @@ $typeTransform{"Frontend"} = { "forward" => "InspectorFrontend", "header" => "InspectorFrontend.h", }; -$typeTransform{"InspectorClient"} = { - "forward" => "InspectorClient", - "header" => "InspectorClient.h", -}; $typeTransform{"PassRefPtr"} = { "forwardHeader" => "wtf/PassRefPtr.h", }; +$typeTransform{"InspectorFrontendChannel"} = { + "forward" => "InspectorFrontendChannel", + "header" => "InspectorFrontendChannel.h", +}; $typeTransform{"Object"} = { "param" => "PassRefPtr<InspectorObject>", "variable" => "RefPtr<InspectorObject>", @@ -105,7 +105,6 @@ $typeTransform{"Object"} = { "header" => "InspectorValues.h", "JSONType" => "Object", "JSType" => "object", - "DocType" => "%s" }; $typeTransform{"Array"} = { "param" => "PassRefPtr<InspectorArray>", @@ -115,7 +114,6 @@ $typeTransform{"Array"} = { "header" => "InspectorValues.h", "JSONType" => "Array", "JSType" => "object", - "DocType" => "array of %s" }; $typeTransform{"Value"} = { "param" => "PassRefPtr<InspectorValue>", @@ -125,7 +123,6 @@ $typeTransform{"Value"} = { "header" => "InspectorValues.h", "JSONType" => "Value", "JSType" => "", - "DocType" => "value" }; $typeTransform{"String"} = { "param" => "const String&", @@ -195,6 +192,9 @@ $typeTransform{"void"} = { "forward" => "", "header" => "" }; +$typeTransform{"Vector"} = { + "header" => "wtf/Vector.h" +}; # Default License Templates @@ -223,6 +223,7 @@ my @backendConstantDeclarations; my @backendConstantDefinitions; my @backendFooter; my @backendJSStubs; +my @backendJSEvents; my %backendDomains; my $frontendClassName; @@ -236,9 +237,6 @@ my @frontendConstantDeclarations; my @frontendConstantDefinitions; my @frontendFooter; -my @documentationToc; -my @documentationLines; - # Default constructor sub new { @@ -267,17 +265,17 @@ sub GenerateModule $namespace =~ s/core/WebCore/; $frontendClassName = "InspectorFrontend"; - $frontendConstructor = " ${frontendClassName}(InspectorClient*);"; + $frontendConstructor = " ${frontendClassName}(InspectorFrontendChannel*);"; push(@frontendFooter, "private:"); - push(@frontendFooter, " InspectorClient* m_inspectorClient;"); + push(@frontendFooter, " InspectorFrontendChannel* m_inspectorFrontendChannel;"); $frontendTypes{"String"} = 1; - $frontendTypes{"InspectorClient"} = 1; + $frontendTypes{"InspectorFrontendChannel"} = 1; $frontendTypes{"PassRefPtr"} = 1; $backendClassName = "InspectorBackendDispatcher"; $backendJSStubName = "InspectorBackendStub"; $backendTypes{"Inspector"} = 1; - $backendTypes{"InspectorClient"} = 1; + $backendTypes{"InspectorFrontendChannel"} = 1; $backendTypes{"PassRefPtr"} = 1; $backendTypes{"Object"} = 1; } @@ -306,10 +304,12 @@ sub generateAgentDeclaration my $agentName = $interface->name; push(@frontendMethods, " class ${agentName} {"); push(@frontendMethods, " public:"); - push(@frontendMethods, " ${agentName}(InspectorClient* inspectorClient) : m_inspectorClient(inspectorClient) { }"); + push(@frontendMethods, " ${agentName}(InspectorFrontendChannel* inspectorFrontendChannel) : m_inspectorFrontendChannel(inspectorFrontendChannel) { }"); push(@frontendMethods, @{$agent->{methodDeclarations}}); + push(@frontendMethods, " void setInspectorFrontendChannel(InspectorFrontendChannel* inspectorFrontendChannel) { m_inspectorFrontendChannel = inspectorFrontendChannel; }"); + push(@frontendMethods, " InspectorFrontendChannel* getInspectorFrontendChannel() { return m_inspectorFrontendChannel; }"); push(@frontendMethods, " private:"); - push(@frontendMethods, " InspectorClient* m_inspectorClient;"); + push(@frontendMethods, " InspectorFrontendChannel* m_inspectorFrontendChannel;"); push(@frontendMethods, " };"); push(@frontendMethods, ""); @@ -325,10 +325,10 @@ sub generateAgentDeclaration sub generateFrontendConstructorImpl { my @frontendConstructorImpl; - push(@frontendConstructorImpl, "${frontendClassName}::${frontendClassName}(InspectorClient* inspectorClient)"); - push(@frontendConstructorImpl, " : m_inspectorClient(inspectorClient)"); + push(@frontendConstructorImpl, "${frontendClassName}::${frontendClassName}(InspectorFrontendChannel* inspectorFrontendChannel)"); + push(@frontendConstructorImpl, " : m_inspectorFrontendChannel(inspectorFrontendChannel)"); foreach my $agentField (@frontendAgentFields) { - push(@frontendConstructorImpl, " , ${agentField}(inspectorClient)"); + push(@frontendConstructorImpl, " , ${agentField}(inspectorFrontendChannel)"); } push(@frontendConstructorImpl, "{"); push(@frontendConstructorImpl, "}"); @@ -348,20 +348,8 @@ sub generateFunctions } } - push(@documentationToc, "<li><a href='#" . $interface->name . "'>" . $interface->name . "</a></li>"); - push(@documentationLines, "<h2 id='" . $interface->name . "'><a name=" . $interface->name . "></a>" . $interface->name . "</h2>"); - - push(@documentationLines, "<h3>Events</h3>"); - foreach my $function (grep($_->signature->extendedAttributes->{"event"}, @{$interface->functions}) ) { - generateDocumentationEvent($interface, $function); - } - - push(@documentationLines, "<h3>Commands</h3>"); - foreach my $function (grep(!$_->signature->extendedAttributes->{"event"}, @{$interface->functions})) { - generateDocumentationCommand($interface, $function); - } - collectBackendJSStubFunctions($interface); + collectBackendJSStubEvents($interface); } sub generateFrontendFunction @@ -386,55 +374,20 @@ sub generateFrontendFunction push(@function, "void ${frontendClassName}::${domain}::${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> bodyObject = InspectorObject::create();"); - my @pushArguments = map(" bodyObject->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @argsFiltered); - push(@function, @pushArguments); - push(@function, " ${functionName}Message->setObject(\"body\", bodyObject);"); - push(@function, " m_inspectorClient->sendMessageToFrontend(${functionName}Message->toJSONString());"); - push(@function, "}"); - push(@function, ""); - push(@frontendMethodsImpl, @function); -} - -sub generateDocumentationEvent -{ - my $interface = shift; - my $function = shift; - - my $functionName = $function->signature->name; - my $domain = $interface->name; - - my @argsFiltered = grep($_->direction eq "out", @{$function->parameters}); - - my @lines; - push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>"); - my $doc = $function->signature->extendedAttributes->{"doc"}; - if ($doc) { - push(@lines, $doc); - } - - push(@lines, "<pre style='background: lightGrey; padding: 10px'>"); - push(@lines, "{"); - push(@lines, " type: \"event\","); - push(@lines, " domain: \"$domain\","); + push(@function, " ${functionName}Message->setString(\"method\", \"$domain.$functionName\");"); if (scalar(@argsFiltered)) { - push(@lines, " event: \"${functionName}\","); - push(@lines, " data: {"); - my @parameters; + push(@function, " RefPtr<InspectorObject> paramsObject = InspectorObject::create();"); + foreach my $parameter (@argsFiltered) { - push(@parameters, " " . parameterDocLine($parameter)); + my $optional = $parameter->extendedAttributes->{"optional"} ? "if (" . $parameter->name . ")\n " : ""; + push(@function, " " . $optional . "paramsObject->set" . typeTraits($parameter->type, "JSONType") . "(\"" . $parameter->name . "\", " . $parameter->name . ");"); } - push(@lines, join(",\n", @parameters)); - push(@lines, " }"); - } else { - push(@lines, " event: \"${functionName}\""); + push(@function, " ${functionName}Message->setObject(\"params\", paramsObject);"); } - push(@lines, "}"); - push(@lines, "</pre>"); - push(@documentationLines, @lines); + push(@function, " m_inspectorFrontendChannel->sendMessageToFrontend(${functionName}Message->toJSONString());"); + push(@function, "}"); + push(@function, ""); + push(@frontendMethodsImpl, @function); } sub camelCase @@ -452,12 +405,13 @@ sub generateBackendFunction my $functionName = $function->signature->name; my $fullQualifiedFunctionName = $interface->name . "_" . $function->signature->name; + my $fullQualifiedFunctionNameDot = $interface->name . "." . $function->signature->name; push(@backendConstantDeclarations, " static const char* ${fullQualifiedFunctionName}Cmd;"); - push(@backendConstantDefinitions, "const char* ${backendClassName}::${fullQualifiedFunctionName}Cmd = \"${fullQualifiedFunctionName}\";"); + push(@backendConstantDefinitions, "const char* ${backendClassName}::${fullQualifiedFunctionName}Cmd = \"${fullQualifiedFunctionNameDot}\";"); map($backendTypes{$_->type} = 1, @{$function->parameters}); # register required types - my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters}); + my @inArgs = grep($_->direction eq "in", @{$function->parameters}); my @outArgs = grep($_->direction eq "out", @{$function->parameters}); my $signature = " void ${fullQualifiedFunctionName}(long callId, InspectorObject* requestMessageObject);"; @@ -477,133 +431,106 @@ sub generateBackendFunction $backendTypes{$domain} = 1; $backendDomains{$domain} = 1; push(@function, " if (!$domainAccessor)"); - push(@function, " protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");"); + push(@function, " protocolErrors->pushString(\"$domain handler is not available.\");"); push(@function, ""); # declare local variables for out arguments. - push(@function, map(" " . typeTraits($_->type, "variable") . " " . $_->name . " = " . typeTraits($_->type, "defaultValue") . ";", @outArgs)); - push(@function, ""); + if (scalar(@outArgs)) { + push(@function, map(" " . typeTraits($_->type, "variable") . " out_" . $_->name . " = " . typeTraits($_->type, "defaultValue") . ";", @outArgs)); + push(@function, ""); + } push(@function, " ErrorString error;"); push(@function, ""); my $indent = ""; if (scalar(@inArgs)) { - push(@function, " if (RefPtr<InspectorObject> argumentsContainer = requestMessageObject->getObject(\"arguments\")) {"); + push(@function, " if (RefPtr<InspectorObject> paramsContainer = requestMessageObject->getObject(\"params\")) {"); foreach my $parameter (@inArgs) { my $name = $parameter->name; my $type = $parameter->type; my $typeString = camelCase($parameter->type); - push(@function, " " . typeTraits($type, "variable") . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());"); + my $optional = $parameter->extendedAttributes->{"optional"} ? "true" : "false"; + push(@function, " " . typeTraits($type, "variable") . " in_$name = get$typeString(paramsContainer.get(), \"$name\", $optional, protocolErrors.get());"); } push(@function, ""); $indent = " "; } - my $args = join(", ", ("&error", map($_->name, @inArgs), map("&" . $_->name, @outArgs))); + + my $args = join(", ", + ("&error", + map(($_->extendedAttributes->{"optional"} ? "&" : "") . "in_" . $_->name, @inArgs), + map("&out_" . $_->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, " } else"); + push(@function, " protocolErrors->pushString(\"'params' 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()) {"); - push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();"); - push(@function, " responseMessage->setNumber(\"requestId\", callId);"); push(@function, ""); - push(@function, " if (protocolErrors->length())"); - push(@function, " responseMessage->setArray(\"protocolErrors\", protocolErrors);"); - if (scalar(@outArgs)) { - push(@function, " else {"); - push(@function, " if (error.length())"); - push(@function, " responseMessage->setString(\"error\", error);"); - push(@function, " RefPtr<InspectorObject> responseBody = InspectorObject::create();"); - push(@function, map(" responseBody->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", " . $_->name . ");", @outArgs)); - push(@function, " responseMessage->setObject(\"body\", responseBody);"); - push(@function, " }"); - } - push(@function, " m_inspectorClient->sendMessageToFrontend(responseMessage->toJSONString());"); + push(@function, " if (protocolErrors->length()) {"); + push(@function, " reportProtocolError(&callId, InvalidParams, protocolErrors);"); + push(@function, " return;"); push(@function, " }"); - - + push(@function, ""); + push(@function, " if (error.length()) {"); + push(@function, " reportProtocolError(&callId, ServerError, error);"); + push(@function, " return;"); + push(@function, " }"); + push(@function, ""); + push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();"); + push(@function, " RefPtr<InspectorObject> result = InspectorObject::create();"); + push(@function, map(" result->set" . typeTraits($_->type, "JSONType") . "(\"" . $_->name . "\", out_" . $_->name . ");", @outArgs)); + push(@function, " responseMessage->setObject(\"result\", result);"); + push(@function, ""); + push(@function, " responseMessage->setNumber(\"id\", callId);"); + push(@function, " m_inspectorFrontendChannel->sendMessageToFrontend(responseMessage->toJSONString());"); push(@function, "}"); push(@function, ""); push(@backendMethodsImpl, @function); } -sub generateDocumentationCommand -{ - my $interface = shift; - my $function = shift; - - my $functionName = $function->signature->name; - my $domain = $interface->name; - - my @lines; - - push(@lines, "<h4>" . $interface->name . "." . ${functionName} . "</h4>"); - my $doc = $function->signature->extendedAttributes->{"doc"}; - if ($doc) { - push(@lines, $doc); - } - - my @inArgs = grep($_->direction eq "in" && !($_->name eq "callId") , @{$function->parameters}); - push(@lines, "<pre style='background: lightGrey; padding: 10px'>"); - push(@lines, "request: {"); - push(@lines, " id: <number>,"); - push(@lines, " type: \"request\","); - push(@lines, " domain: \"" . $interface->name . "\","); - if (scalar(@inArgs)) { - push(@lines, " command: \"${functionName}\","); - push(@lines, " arguments: {"); - my @parameters; - foreach my $parameter (@inArgs) { - push(@parameters, " " . parameterDocLine($parameter)); - } - push(@lines, join(",\n", @parameters)); - push(@lines, " }"); - } else { - push(@lines, " command: \"${functionName}\""); - } - push(@lines, "}"); - - my @outArgs = grep($_->direction eq "out", @{$function->parameters}); - push(@lines, ""); - push(@lines, "response: {"); - push(@lines, " requestId: <number>,"); - if (scalar(@outArgs)) { - push(@lines, " type: \"response\","); - push(@lines, " body: {"); - my @parameters; - foreach my $parameter (@outArgs) { - push(@parameters, " " . parameterDocLine($parameter)); - } - push(@lines, join(",\n", @parameters)); - push(@lines, " }"); - } else { - push(@lines, " type: \"response\""); - } - push(@lines, "}"); - push(@lines, "</pre>"); - - push(@documentationLines, @lines); -} - sub generateBackendReportProtocolError { my $reportProtocolError = << "EOF"; -void ${backendClassName}::reportProtocolError(const long callId, const String& errorText) const +void ${backendClassName}::reportProtocolError(const long* const callId, CommonErrorCode code, const String& customText) const { + RefPtr<InspectorArray> data = InspectorArray::create(); + data->pushString(customText); + reportProtocolError(callId, code, data.release()); +} + +void ${backendClassName}::reportProtocolError(const long* const callId, CommonErrorCode code, PassRefPtr<InspectorArray> data) const +{ + DEFINE_STATIC_LOCAL(Vector<String>,s_commonErrors,); + if (!s_commonErrors.size()) { + s_commonErrors.insert(ParseError, "{\\\"code\\\":-32700,\\\"message\\\":\\\"Parse error.\\\"}"); + s_commonErrors.insert(InvalidRequest, "{\\\"code\\\":-32600,\\\"message\\\":\\\"Invalid Request.\\\"}"); + s_commonErrors.insert(MethodNotFound, "{\\\"code\\\":-32601,\\\"message\\\":\\\"Method not found.\\\"}"); + s_commonErrors.insert(InvalidParams, "{\\\"code\\\":-32602,\\\"message\\\":\\\"Invalid params.\\\"}"); + s_commonErrors.insert(InternalError, "{\\\"code\\\":-32603,\\\"message\\\":\\\"Internal error.\\\"}"); + s_commonErrors.insert(ServerError, "{\\\"code\\\":-32000,\\\"message\\\":\\\"Server error.\\\"}"); + } + ASSERT(code >=0); + ASSERT((unsigned)code < s_commonErrors.size()); + ASSERT(s_commonErrors[code]); + ASSERT(InspectorObject::parseJSON(s_commonErrors[code])); + RefPtr<InspectorObject> error = InspectorObject::parseJSON(s_commonErrors[code])->asObject(); + ASSERT(error); + error->setArray("data", data); RefPtr<InspectorObject> message = InspectorObject::create(); - message->setNumber("requestId", callId); - RefPtr<InspectorArray> errors = InspectorArray::create(); - errors->pushString(errorText); - message->setArray("protocolErrors", errors); - m_inspectorClient->sendMessageToFrontend(message->toJSONString()); + message->setObject("error", error); + if (callId) + message->setNumber("id", *callId); + else + message->setValue("id", InspectorValue::null()); + m_inspectorFrontendChannel->sendMessageToFrontend(message->toJSONString()); } EOF return split("\n", $reportProtocolError); @@ -618,10 +545,10 @@ sub generateArgumentGetters my $return = typeTraits($type, "return") ? typeTraits($type, "return") : typeTraits($type, "param"); my $typeString = camelCase($type); - push(@backendConstantDeclarations, " $return get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors);"); + push(@backendConstantDeclarations, " $return get$typeString(InspectorObject* object, const String& name, bool optional, InspectorArray* protocolErrors);"); my $getterBody = << "EOF"; -$return InspectorBackendDispatcher::get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors) +$return InspectorBackendDispatcher::get$typeString(InspectorObject* object, const String& name, bool optional, InspectorArray* protocolErrors) { ASSERT(object); ASSERT(protocolErrors); @@ -630,12 +557,14 @@ $return InspectorBackendDispatcher::get$typeString(InspectorObject* object, cons 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())); + if (valueIterator == end) { + if (!optional) + protocolErrors->pushString(String::format("Parameter '\%s' with type '$json' was not found.", name.utf8().data())); + return value; } + + if (!valueIterator->second->as$json(&value)) + protocolErrors->pushString(String::format("Parameter '\%s' has wrong type. It should be '$json'.", name.utf8().data())); return value; } EOF @@ -650,11 +579,6 @@ sub generateBackendDispatcher my $mapEntries = join("\n", @mapEntries); my $backendDispatcherBody = << "EOF"; -static String commandName(const String& domain, const String& command) -{ - return makeString(domain, "_", command); -} - void ${backendClassName}::dispatch(const String& message) { typedef void (${backendClassName}::*CallHandler)(long callId, InspectorObject* messageObject); @@ -668,54 +592,42 @@ $mapEntries RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message); if (!parsedMessage) { - reportProtocolError(callId, "Protocol Error: Invalid message format. Message should be in JSON format."); + reportProtocolError(0, ParseError, "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."); + reportProtocolError(0, InvalidRequest, "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> domainValue = messageObject->get("domain"); - if (!domainValue) { - reportProtocolError(callId, "Protocol Error: Invalid message format. 'domain' property wasn't found."); + RefPtr<InspectorValue> callIdValue = messageObject->get("id"); + if (!callIdValue) { + reportProtocolError(0, InvalidRequest, "Invalid message format. 'id' property was not found in the request."); return; } - String domain; - if (!domainValue->asString(&domain)) { - reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'domain' property should be string."); + if (!callIdValue->asNumber(&callId)) { + reportProtocolError(0, InvalidRequest, "Invalid message format. The type of 'id' property should be number."); return; } - RefPtr<InspectorValue> callIdValue = messageObject->get("id"); - if (!callIdValue) { - reportProtocolError(callId, "Protocol Error: Invalid message format. 'id' property was not found in the request."); + RefPtr<InspectorValue> methodValue = messageObject->get("method"); + if (!methodValue) { + reportProtocolError(&callId, InvalidRequest, "Invalid message format. 'method' property wasn't found."); return; } - if (!callIdValue->asNumber(&callId)) { - reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'id' property should be number."); + String method; + if (!methodValue->asString(&method)) { + reportProtocolError(&callId, InvalidRequest, "Invalid message format. The type of 'method' property should be string."); return; } - HashMap<String, CallHandler>::iterator it = dispatchMap.find(commandName(domain, command)); + HashMap<String, CallHandler>::iterator it = dispatchMap.find(method); if (it == dispatchMap.end()) { - reportProtocolError(callId, makeString("Protocol Error: Invalid command was received. '", command, "' wasn't found in domain ", domain, ".")); + reportProtocolError(&callId, MethodNotFound, makeString("Invalid method name was received. '", method, "' wasn't found.")); return; } @@ -738,15 +650,9 @@ bool ${backendClassName}::getCommandName(const String& message, String* result) if (!object) return false; - String domain; - if (!object->getString("domain", &domain)) + if (!object->getString("method", result)) return false; - String command; - if (!object->getString("command", &command)) - return false; - - *result = commandName(domain, command); return true; } EOF @@ -761,19 +667,40 @@ sub collectBackendJSStubFunctions foreach my $function (@functions) { my $name = $function->signature->name; - my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . typeTraits($_->type, "JSType") . "\"", grep($_->direction eq "in", @{$function->parameters}))); + my @inArgs = grep($_->direction eq "in", @{$function->parameters}); + my $argumentNames = join( + ",", + map("\"" . $_->name . "\": {" + . "\"optional\": " . ($_->extendedAttributes->{"optional"} ? "true " : "false") . ", " + . "\"type\": \"" . typeTraits($_->type, "JSType") . "\"" + . "}", + @inArgs)); push(@backendJSStubs, " this._registerDelegate('{" . - "\"id\": 0, " . - "\"domain\": \"$domain\", " . - "\"command\": \"$name\", " . - "\"arguments\": {$argumentNames}" . + "\"method\": \"$domain.$name\", " . + (scalar(@inArgs) ? "\"params\": {$argumentNames}, " : "") . + "\"id\": 0" . "}');"); } } +sub collectBackendJSStubEvents +{ + my $interface = shift; + my @functions = grep($_->signature->extendedAttributes->{"event"}, @{$interface->functions}); + my $domain = $interface->name; + + foreach my $function (@functions) { + my $name = $domain . "." . $function->signature->name; + my @outArgs = grep($_->direction eq "out", @{$function->parameters}); + my $argumentNames = join(",", map("\"" . $_->name . "\"" , @outArgs)); + push(@backendJSEvents, " this._eventArgs[\"" . $name . "\"] = [" . $argumentNames ."];"); + } +} + sub generateBackendStubJS { my $JSStubs = join("\n", @backendJSStubs); + my $JSEvents = join("\n", @backendJSEvents); my $inspectorBackendStubJS = << "EOF"; $licenseTemplate @@ -783,7 +710,9 @@ InspectorBackendStub = function() this._pendingResponsesCount = 0; this._callbacks = {}; this._domainDispatchers = {}; + this._eventArgs = {}; $JSStubs +$JSEvents } InspectorBackendStub.prototype = { @@ -794,40 +723,53 @@ InspectorBackendStub.prototype = { return callbackId; }, - _registerDelegate: function(commandInfo) + _registerDelegate: function(requestString) { - var commandObject = JSON.parse(commandInfo); - var agentName = commandObject.domain + "Agent"; + var domainAndFunction = JSON.parse(requestString).method.split("."); + var agentName = domainAndFunction[0] + "Agent"; if (!window[agentName]) window[agentName] = {}; - window[agentName][commandObject.command] = this.sendMessageToBackend.bind(this, commandInfo); + window[agentName][domainAndFunction[1]] = this.sendMessageToBackend.bind(this, requestString); }, sendMessageToBackend: function() { var args = Array.prototype.slice.call(arguments); var request = JSON.parse(args.shift()); + var callback = (args.length && typeof args[args.length - 1] === "function") ? args.pop() : 0; + var domainAndMethod = request.method.split("."); + var agentMethod = domainAndMethod[0] + "Agent." + domainAndMethod[1]; + + if (request.params) { + for (var key in request.params) { + var typeName = request.params[key].type; + var optionalFlag = request.params[key].optional; + + if (args.length === 0 && !optionalFlag) { + console.error("Protocol Error: Invalid number of arguments for method '" + agentMethod + "' call. It should have the next arguments '" + JSON.stringify(request.params) + "'."); + return; + } - for (var key in request.arguments) { - if (args.length === 0) { - 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) + "'."); - return; - } - var value = args.shift(); - if (request.arguments[key] && typeof value !== request.arguments[key]) { - 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 + "'."); - return; + var value = args.shift(); + if (optionalFlag && typeof value === "undefined") { + delete request.params[key]; + continue; + } + + if (typeof value !== typeName) { + console.error("Protocol Error: Invalid type of argument '" + key + "' for method '" + agentMethod + "' call. It should be '" + typeName + "' but it is '" + typeof value + "'."); + return; + } + + request.params[key] = value; } - request.arguments[key] = value; } - var callback; - if (args.length === 1) { - if (typeof args[0] !== "function" && typeof args[0] !== "undefined") { - 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] + "'."); + if (args.length === 1 && !callback) { + if (typeof args[0] !== "undefined") { + console.error("Protocol Error: Optional callback argument for method '" + agentMethod + "' call should be a function but its type is '" + typeof args[0] + "'."); return; } - callback = args[0]; } request.id = this._wrap(callback || function() {}); @@ -852,51 +794,64 @@ InspectorBackendStub.prototype = { var messageObject = (typeof message === "string") ? JSON.parse(message) : message; - var arguments = []; - if (messageObject.body) - for (var key in messageObject.body) - arguments.push(messageObject.body[key]); - - if ("requestId" in messageObject) { // just a response for some request - if (messageObject.protocolErrors) + if ("id" in messageObject) { // just a response for some request + if (messageObject.error && messageObject.error.code !== -32000) this.reportProtocolError(messageObject); - var callback = this._callbacks[messageObject.requestId]; + var arguments = []; + if (messageObject.result) { + for (var key in messageObject.result) + arguments.push(messageObject.result[key]); + } + + var callback = this._callbacks[messageObject.id]; if (callback) { - if (!messageObject.protocolErrors) { - arguments.unshift(messageObject.error); - callback.apply(null, arguments); - } + arguments.unshift(messageObject.error); + callback.apply(null, arguments); --this._pendingResponsesCount; - delete this._callbacks[messageObject.requestId]; + delete this._callbacks[messageObject.id]; } if (this._scripts && !this._pendingResponsesCount) this.runAfterPendingDispatches(); return; - } - - if (messageObject.type === "event") { - if (!(messageObject.domain in this._domainDispatchers)) { - console.error("Protocol Error: the message is for non-existing domain '" + messageObject.domain + "'"); + } else { + var method = messageObject.method.split("."); + var domainName = method[0]; + var functionName = method[1]; + if (!(domainName in this._domainDispatchers)) { + console.error("Protocol Error: the message is for non-existing domain '" + domainName + "'"); + return; + } + var dispatcher = this._domainDispatchers[domainName]; + if (!(functionName in dispatcher)) { + console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.method + "'"); return; } - var dispatcher = this._domainDispatchers[messageObject.domain]; - if (!(messageObject.event in dispatcher)) { - console.error("Protocol Error: Attempted to dispatch an unimplemented method '" + messageObject.domain + "." + messageObject.event + "'"); + + if (!this._eventArgs[messageObject.method]) { + console.error("Protocol Error: Attempted to dispatch an unspecified method '" + messageObject.method + "'"); return; } - dispatcher[messageObject.event].apply(dispatcher, arguments); + var params = []; + if (messageObject.params) { + var paramNames = this._eventArgs[messageObject.method]; + for (var i = 0; i < paramNames.length; ++i) + params.push(messageObject.params[paramNames[i]]); + } + + dispatcher[functionName].apply(dispatcher, params); } }, reportProtocolError: function(messageObject) { - console.error("Protocol Error: InspectorBackend request with id = " + messageObject.requestId + " failed."); - for (var i = 0; i < messageObject.protocolErrors.length; ++i) - console.error(" " + messageObject.protocolErrors[i]); + var error = messageObject.error; + console.error(error.message + "(" + error.code + "): request with id = " + messageObject.id + " failed."); + for (var i = 0; i < error.data.length; ++i) + console.error(" " + error.data[i]); }, runAfterPendingDispatches: function(script) @@ -1010,44 +965,14 @@ sub typeTraits return $typeTransform{$type}->{$trait}; } -sub parameterDocType -{ - my $parameter = shift; - my $subtype = $parameter->extendedAttributes->{"type"}; - if ($subtype) { - my $pattern = typeTraits($parameter->type, "DocType"); - return sprintf($pattern, "<$subtype>"); - } - - my $subtypeRef = $parameter->extendedAttributes->{"typeRef"}; - if ($subtypeRef) { - my $pattern = typeTraits($parameter->type, "DocType"); - return sprintf($pattern, "<<a href='#$subtypeRef'>" . $subtypeRef . "</a>>"); - } - - return "<" . typeTraits($parameter->type, "JSType") . ">"; -} - -sub parameterDocLine -{ - my $parameter = shift; - - my $result = $parameter->name . ": " . parameterDocType($parameter); - my $doc = $parameter->extendedAttributes->{"doc"}; - if ($doc) { - $result = $result . " // " . $doc; - } - return $result; -} - sub generateBackendAgentFieldsAndConstructor { my @arguments; my @fieldInitializers; - push(@arguments, "InspectorClient* inspectorClient"); - push(@fieldInitializers, " : m_inspectorClient(inspectorClient)"); - push(@backendFooter, " InspectorClient* m_inspectorClient;"); + push(@arguments, "InspectorFrontendChannel* inspectorFrontendChannel"); + push(@fieldInitializers, " : m_inspectorFrontendChannel(inspectorFrontendChannel)"); + push(@backendFooter, " InspectorFrontendChannel* m_inspectorFrontendChannel;"); foreach my $domain (sort keys %backendDomains) { # Add agent field declaration to the footer. @@ -1067,7 +992,19 @@ sub generateBackendAgentFieldsAndConstructor push(@backendHead, " ${backendClassName}(${argumentString})"); push(@backendHead, @fieldInitializers); push(@backendHead, " { }"); - push(@backendHead, " void reportProtocolError(const long callId, const String& errorText) const;"); + push(@backendHead, ""); + push(@backendHead, " enum CommonErrorCode {"); + push(@backendHead, " ParseError = 0,"); + push(@backendHead, " InvalidRequest,"); + push(@backendHead, " MethodNotFound,"); + push(@backendHead, " InvalidParams,"); + push(@backendHead, " InternalError,"); + push(@backendHead, " ServerError,"); + push(@backendHead, " LastEntry,"); + push(@backendHead, " };"); + push(@backendHead, ""); + push(@backendHead, " void reportProtocolError(const long* const callId, CommonErrorCode, const String& errorText) const;"); + push(@backendHead, " void reportProtocolError(const long* const callId, CommonErrorCode, PassRefPtr<InspectorArray> data) const;"); push(@backendHead, " void dispatch(const String& message);"); push(@backendHead, " static bool getCommandName(const String& message, String* result);"); $backendConstructor = join("\n", @backendHead); @@ -1121,14 +1058,6 @@ sub finish print $JS_STUB join("\n", generateBackendStubJS()); close($JS_STUB); undef($JS_STUB); - - open(my $DOCS, ">$outputDir/WebInspectorProtocol.html") || die "Couldn't open file $outputDir/WebInspectorProtocol.html"; - print $DOCS "<ol class='toc' style='list-style: none; padding: 0'>"; - print $DOCS join("\n", @documentationToc); - print $DOCS "</ol>"; - print $DOCS join("\n", @documentationLines); - close($DOCS); - undef($DOCS); } 1; |