📄 codegeneratorcom.pm
字号:
my $noReturn = ($returnType eq "void"); my $newline = $$options{"NewLines"} ? "\n" : ""; my $indent = $$options{"Indent"} ? " " x $$options{"Indent"} : ""; my $semicolon = $$options{"IncludeSemiColon"} ? ";" : ""; my $virtual = $$options{"AddVirtualKeyword"} ? "virtual " : ""; my $class = $$options{"UseClassName"} ? "${className}::" : ""; my $forwarder = $$options{"Forwarder"} ? 1 : 0; my $joiner = ($$options{"NewLines"} ? "\n" . $indent . " " : " "); my @paramArgList = (); foreach my $param (@{$function->parameters}) { my $paramName = $param->name; my $paramType = GetCOMTypeIn($param->type); my $parameter = "/* [in] */ ${paramType} ${paramName}"; push(@paramArgList, $parameter); } unless ($noReturn) { my $resultParameter .= "/* [out, retval] */ ${returnType}* result"; push(@paramArgList, $resultParameter); } my $functionSig = $indent . $virtual . "HRESULT STDMETHODCALLTYPE " . $class . $functionName . "("; $functionSig .= $joiner . join("," . $joiner, @paramArgList) if @paramArgList > 0; $functionSig .= ")" . $semicolon . $newline; if ($forwarder) { my @paramNameList = (); push(@paramNameList, $_->name) foreach (@{$function->parameters}); push(@paramNameList, "result") unless $noReturn; $functionSig .= " { return " . $$options{"Forwarder"} . "::" . $functionName . "(" . join(", ", @paramNameList) . "); }\n"; } return $functionSig}sub GenerateCPPFunction{ my ($function, $className, $implementationClass) = @_; my @functionImplementation = (); my $signature = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1, "Indent" => 0, "IncludeSemiColon" => 0, "UseClassName" => 1, "AddVirtualKeyword" => 0 }); my $implementationClassWithoutNamespace = StripNamespace($implementationClass); my $functionName = $function->signature->name; my $returnIDLType = $function->signature->type; my $noReturn = ($returnIDLType eq "void"); my $raisesExceptions = @{$function->raisesExceptions}; AddIncludesForTypeInCPPImplementation($returnIDLType); $CPPImplementationWebCoreIncludes{"ExceptionCode.h"} = 1 if $raisesExceptions; my %needsCustom = (); my @parameterInitialization = (); my @parameterList = (); foreach my $param (@{$function->parameters}) { my $paramName = $param->name; my $paramIDLType = $param->type; my $paramTypeIsPrimitive = $codeGenerator->IsPrimitiveType($paramIDLType); my $paramTypeIsString = $codeGenerator->IsStringType($paramIDLType); $needsCustom{"NodeToReturn"} = $paramName if $param->extendedAttributes->{"Return"}; AddIncludesForTypeInCPPImplementation($paramIDLType); # FIXME: We may need to null check the arguments as well if ($paramTypeIsString) { push(@parameterList, $paramName); } elsif ($paramTypeIsPrimitive) { if ($paramIDLType eq "boolean") { push(@parameterList, "!!${paramName}"); } else { my $primitiveImplementationType = IDLTypeToImplementationType($paramIDLType); push(@parameterList, "static_cast<${primitiveImplementationType}>(${paramName})"); } } else { $CPPImplementationWebCoreIncludes{"COMPtr.h"} = 1; $needsCustom{"CanReturnEarly"} = 1; my $paramTypeCOMClassName = GetClassName($paramIDLType); my $paramTypeImplementationWithoutNamespace = StripNamespace(IDLTypeToImplementationType($paramIDLType)); my $ptrName = "ptrFor" . $codeGenerator->WK_ucfirst($paramName); my $paramInit = " COMPtr<${paramTypeCOMClassName}> ${ptrName}(Query, ${paramName});\n"; $paramInit .= " if (!${ptrName})\n"; $paramInit .= " return E_NOINTERFACE;"; push(@parameterInitialization, $paramInit); push(@parameterList, "${ptrName}->impl${paramTypeImplementationWithoutNamespace}()"); } } push(@parameterList, "ec") if $raisesExceptions; my $implementationGetter = "impl${implementationClassWithoutNamespace}()"; my $callSigBegin = " "; my $callSigMiddle = "${implementationGetter}->" . $codeGenerator->WK_lcfirst($functionName) . "(" . join(", ", @parameterList) . ")"; my $callSigEnd = ";\n"; if (defined $needsCustom{"NodeToReturn"}) { my $nodeToReturn = $needsCustom{"NodeToReturn"}; $callSigBegin .= "if ("; $callSigEnd = ")\n"; $callSigEnd .= " *result = ${nodeToReturn};"; } elsif (!$noReturn) { my $returnTypeIsString = $codeGenerator->IsStringType($returnIDLType); my $returnTypeIsPrimitive = $codeGenerator->IsPrimitiveType($returnIDLType); if ($returnTypeIsString) { $callSigBegin .= "*result = WebCore::BString("; $callSigEnd = ").release();\n"; } elsif ($returnTypeIsPrimitive) { my $primitiveCOMType = GetClassName($returnIDLType); $callSigBegin .= "*result = static_cast<${primitiveCOMType}>("; $callSigEnd = ");"; } else { $CPPImplementationIncludesAngle{"wtf/GetPtr.h"} = 1; my $returnImplementationType = IDLTypeToImplementationType($returnIDLType); my $returnTypeCOMInterfaceName = GetInterfaceName($returnIDLType); $callSigBegin .= "${returnImplementationType}* resultImpl = WTF::getPtr("; $callSigEnd = ");\n"; $callSigEnd .= " if (!resultImpl)\n"; $callSigEnd .= " return E_POINTER;\n\n"; $callSigEnd .= " *result = to${returnTypeCOMInterfaceName}(resultImpl);"; } } push(@functionImplementation, $signature); push(@functionImplementation, "{\n"); unless ($noReturn) { push(@functionImplementation, " if (!result)\n"); push(@functionImplementation, " return E_POINTER;\n\n"); push(@functionImplementation, " *result = 0;\n\n") if $needsCustom{"CanReturnEarly"}; } push(@functionImplementation, " WebCore::ExceptionCode ec = 0;\n") if $raisesExceptions; # FIXME: CHECK EXCEPTION AND DO SOMETHING WITH IT push(@functionImplementation, join("\n", @parameterInitialization) . (@parameterInitialization > 0 ? "\n" : "")); push(@functionImplementation, $callSigBegin . $callSigMiddle . $callSigEnd . "\n"); push(@functionImplementation, " return S_OK;\n"); push(@functionImplementation, "}\n\n"); return join("", @functionImplementation);}# -----------------------------------------------------------------------------# CPP Header# -----------------------------------------------------------------------------sub GenerateCPPHeader{ my ($object, $dataNode) = @_; my $IDLType = $dataNode->name; my $implementationClass = IDLTypeToImplementationType($IDLType); my $implementationClassWithoutNamespace = StripNamespace($implementationClass); my $className = GetClassName($IDLType); my $interfaceName = GetInterfaceName($IDLType); my $parentClassName = GetParentClass($dataNode); my @otherInterfacesImplemented = GetAdditionalInterfaces($IDLType); foreach my $otherInterface (@otherInterfacesImplemented) { push(@additionalInterfaceDefinitions, $codeGenerator->ParseInterface($otherInterface)); } # FIXME: strip whitespace from UUID my $uuid = $dataNode->extendedAttributes->{"ImplementationUUID"} || die "All classes require an ImplementationUUID extended attribute."; my $numAttributes = @{$dataNode->attributes}; my $numFunctions = @{$dataNode->functions}; # - Add default header template @CPPHeaderHeader = @licenseTemplate; push(@CPPHeaderHeader, "\n"); # - Header guards - push(@CPPHeaderHeader, "#ifndef " . $className . "_h\n"); push(@CPPHeaderHeader, "#define " . $className . "_h\n\n"); AddIncludesForTypeInCPPHeader($interfaceName); AddIncludesForTypeInCPPHeader($parentClassName); $CPPHeaderDontForwardDeclarations{$className} = 1; $CPPHeaderDontForwardDeclarations{$interfaceName} = 1; $CPPHeaderDontForwardDeclarations{$parentClassName} = 1; # -- Forward declare implementation type push(@CPPHeaderContent, "namespace WebCore {\n"); push(@CPPHeaderContent, " class ". StripNamespace($implementationClass) . ";\n"); push(@CPPHeaderContent, "}\n\n"); # -- Start Class -- my @parentsClasses = ($parentClassName, $interfaceName); push(@parentsClasses, map { GetInterfaceName($_) } @otherInterfacesImplemented); push(@CPPHeaderContent, "class __declspec(uuid(\"$uuid\")) ${className} : " . join(", ", map { "public $_" } @parentsClasses) . " {\n"); # Add includes for all additional interfaces to implement map { AddIncludesForTypeInCPPHeader(GetInterfaceName($_)) } @otherInterfacesImplemented; # -- BASICS -- # FIXME: The constructor and destructor should be protected, but the current design of # createInstance requires them to be public. One solution is to friend the constructor # of the top-level-class with every one of its child classes, but that requires information # this script currently does not have, though possibly could determine. push(@CPPHeaderContent, "public:\n"); push(@CPPHeaderContent, " ${className}(${implementationClass}*);\n"); push(@CPPHeaderContent, " virtual ~${className}();\n\n"); push(@CPPHeaderContent, "public:\n"); push(@CPPHeaderContent, " static ${className}* createInstance(${implementationClass}*);\n\n"); push(@CPPHeaderContent, " // IUnknown\n"); push(@CPPHeaderContent, " virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, void** ppvObject);\n"); push(@CPPHeaderContent, " virtual ULONG STDMETHODCALLTYPE AddRef() { return ${parentClassName}::AddRef(); }\n"); push(@CPPHeaderContent, " virtual ULONG STDMETHODCALLTYPE Release() { return ${parentClassName}::Release(); }\n\n"); # -- Parent Class Forwards -- if (@{$dataNode->parents}) { my %attributeNameSet = map {($_->signature->name, 1)} @{$dataNode->attributes}; my %functionNameSet = map {($_->signature->name, 1)} @{$dataNode->functions}; my @parentLists = $codeGenerator->GetMethodsAndAttributesFromParentClasses($dataNode); push(@CPPHeaderContent, "\n"); foreach my $parentHash (@parentLists) { push(@CPPHeaderContent, " // " . GetInterfaceName($parentHash->{'name'}) . $DASHES . "\n"); my @attributeList = @{$parentHash->{'attributes'}}; push(@CPPHeaderContent, " // Attributes\n"); foreach my $attribute (@attributeList) { # Don't forward an attribute that this class redefines. next if $attributeNameSet{$attribute->signature->name}; AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type); my %attributes = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 0, "Indent" => 4, "IncludeSemiColon" => 0, "AddVirtualKeyword" => 1, "UseClassName" => 0, "Forwarder" => $parentClassName }); push(@CPPHeaderContent, values(%attributes)); } # Add attribute names to attribute names set in case other ancestors # also define them. $attributeNameSet{$_->signature->name} = 1 foreach @attributeList; push(@CPPHeaderContent, "\n"); my @functionList = @{$parentHash->{'functions'}}; push(@CPPHeaderContent, " // Functions\n"); foreach my $function (@functionList) { # Don't forward a function that this class redefines. next if $functionNameSet{$function->signature->name}; AddForwardDeclarationsForTypeInCPPHeader($function->signature->type); AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters}); my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 0, "Indent" => 4, "IncludeSemiColon" => 0, "AddVirtualKeyword" => 1, "UseClassName" => 0, "Forwarder" => $parentClassName }); push(@CPPHeaderContent, $functionSig); } # Add functions names to functions names set in case other ancestors # also define them. $functionNameSet{$_->signature->name} = 1 foreach @functionList; push(@CPPHeaderContent, "\n"); } } # - Additional interfaces to implement - foreach my $interfaceToImplement (@additionalInterfaceDefinitions) { my $IDLTypeOfInterfaceToImplement = $interfaceToImplement->name; my $nameOfInterfaceToImplement = GetInterfaceName($IDLTypeOfInterfaceToImplement); my $numAttributesInInterface = @{$interfaceToImplement->attributes}; my $numFunctionsInInterface = @{$interfaceToImplement->functions}; push(@CPPHeaderContent, " // ${nameOfInterfaceToImplement} ${DASHES}\n\n"); # - Add attribute getters/setters. if ($numAttributesInInterface > 0) { push(@CPPHeaderContent, " // Attributes\n\n"); foreach my $attribute (@{$interfaceToImplement->attributes}) { AddForwardDeclarationsForTypeInCPPHeader($attribute->signature->type); my %attributeSigs = GenerateCPPAttributeSignature($attribute, $className, { "NewLines" => 1, "Indent" => 4, "IncludeSemiColon" => 1, "AddVirtualKeyword" => 1, "UseClassName" => 0 }); push(@CPPHeaderContent, values(%attributeSigs)); push(@CPPHeaderContent, "\n"); } } # - Add functions. if ($numFunctionsInInterface > 0) { push(@CPPHeaderContent, " // Functions\n\n"); foreach my $function (@{$interfaceToImplement->functions}) { AddForwardDeclarationsForTypeInCPPHeader($function->signature->type); AddForwardDeclarationsForTypeInCPPHeader($_->type) foreach (@{$function->parameters}); my $functionSig = GenerateCPPFunctionSignature($function, $className, { "NewLines" => 1, "Indent" => 4, "IncludeSemiColon" => 1, "AddVirtualKeyword" => 1, "UseClassName" => 0 }); push(@CPPHeaderContent, $functionSig); push(@CPPHeaderContent, "\n"); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -