diff options
Diffstat (limited to 'V8Binding/scripts')
-rw-r--r-- | V8Binding/scripts/CodeGenerator.pm | 334 | ||||
-rw-r--r-- | V8Binding/scripts/CodeGeneratorV8.pm | 2178 | ||||
-rw-r--r-- | V8Binding/scripts/IDLParser.pm | 441 | ||||
-rw-r--r-- | V8Binding/scripts/generate-bindings.pl | 69 |
4 files changed, 3022 insertions, 0 deletions
diff --git a/V8Binding/scripts/CodeGenerator.pm b/V8Binding/scripts/CodeGenerator.pm new file mode 100644 index 0000000..d115459 --- /dev/null +++ b/V8Binding/scripts/CodeGenerator.pm @@ -0,0 +1,334 @@ +# +# KDOM IDL parser +# +# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org> +# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> +# +# This file is part of the KDE project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package CodeGenerator; + +my $useDocument = ""; +my $useGenerator = ""; +my $useOutputDir = ""; +my $useDirectories = ""; +my $useLayerOnTop = 0; +my $preprocessor; + +my $codeGenerator = 0; + +my $verbose = 0; + +my %primitiveTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1, + "unsigned int" => 1, "unsigned short" => 1, + "unsigned long" => 1, "float" => 1, + "unsigned long long" => 1, + "double" => 1, "boolean" => 1, "void" => 1); + +my %podTypeHash = ("SVGNumber" => 1, "SVGTransform" => 1); +my %podTypeWithWriteablePropertiesHash = ("SVGLength" => 1, "SVGMatrix" => 1, "SVGPoint" => 1, "SVGRect" => 1); +my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1); + +my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1, "SVGPaintType" => 1); + +my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1, + "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1, + "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1, + "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1, + "SVGAnimatedPreserveAspectRatio" => 1, + "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1, + "SVGAnimatedTransformList" => 1); + +# Helpers for 'ScanDirectory' +my $endCondition = 0; +my $foundFilename = ""; +my @foundFilenames = (); +my $ignoreParent = 1; +my $defines = ""; + +# Default constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $useDirectories = shift; + $useGenerator = shift; + $useOutputDir = shift; + $useLayerOnTop = shift; + $preprocessor = shift; + + bless($reference, $object); + return $reference; +} + +sub StripModule($) +{ + my $object = shift; + my $name = shift; + $name =~ s/[a-zA-Z0-9]*:://; + return $name; +} + +sub ProcessDocument +{ + my $object = shift; + $useDocument = shift; + $defines = shift; + + my $ifaceName = "CodeGenerator" . $useGenerator; + + # Dynamically load external code generation perl module + require $ifaceName . ".pm"; + $codeGenerator = $ifaceName->new($object, $useOutputDir, $useLayerOnTop, $preprocessor); + unless (defined($codeGenerator)) { + my $classes = $useDocument->classes; + foreach my $class (@$classes) { + print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n" if $verbose; + } + return; + } + + # Start the actual code generation! + $codeGenerator->GenerateModule($useDocument, $defines); + + my $classes = $useDocument->classes; + foreach my $class (@$classes) { + print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n" if $verbose; + $codeGenerator->GenerateInterface($class, $defines); + $codeGenerator->finish(); + } +} + + +sub FindParentsRecursively +{ + my $object = shift; + my $dataNode = shift; + my @parents = ($dataNode->name); + foreach (@{$dataNode->parents}) { + my $interface = $object->StripModule($_); + + $endCondition = 0; + $foundFilename = ""; + foreach (@{$useDirectories}) { + $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq ""); + } + + if ($foundFilename ne "") { + print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; + + # Step #2: Parse the found IDL file (in quiet mode). + my $parser = IDLParser->new(1); + my $document = $parser->ParseInheritance($foundFilename, $defines, $preprocessor); + + foreach my $class (@{$document->classes}) { + @parents = (@parents, FindParentsRecursively($object, $class)); + } + } else { + die("Could NOT find specified parent interface \"$interface\"!\n") + } + } + return @parents; +} + + +sub AddMethodsConstantsAndAttributesFromParentClasses +{ + # For the passed interface, recursively parse all parent + # IDLs in order to find out all inherited properties/methods. + + my $object = shift; + my $dataNode = shift; + + my @parents = @{$dataNode->parents}; + my $parentsMax = @{$dataNode->parents}; + + my $constantsRef = $dataNode->constants; + my $functionsRef = $dataNode->functions; + my $attributesRef = $dataNode->attributes; + + # Exception: For the DOM 'Node' is our topmost baseclass, not EventTargetNode. + foreach (@{$dataNode->parents}) { + my $interface = $object->StripModule($_); + + # Don't ignore the first class EventTarget + if ($interface ne "EventTarget" && $ignoreParent) { + # Ignore first parent class, already handled by the generation itself. + $ignoreParent = 0; + next; + } + + # Step #1: Find the IDL file associated with 'interface' + $endCondition = 0; + $foundFilename = ""; + + foreach (@{$useDirectories}) { + $object->ScanDirectory("$interface.idl", $_, $_, 0) if ($foundFilename eq ""); + } + + if ($foundFilename ne "") { + print " | |> Parsing parent IDL \"$foundFilename\" for interface \"$interface\"\n" if $verbose; + + # Step #2: Parse the found IDL file (in quiet mode). + my $parser = IDLParser->new(1); + my $document = $parser->Parse($foundFilename, $defines, $preprocessor); + + foreach my $class (@{$document->classes}) { + # Step #3: Enter recursive parent search + AddMethodsConstantsAndAttributesFromParentClasses($object, $class); + + # Step #4: Collect constants & functions & attributes of this parent-class + my $constantsMax = @{$class->constants}; + my $functionsMax = @{$class->functions}; + my $attributesMax = @{$class->attributes}; + + print " | |> -> Inheriting $constantsMax constants, $functionsMax functions, $attributesMax attributes...\n | |>\n" if $verbose; + + # Step #5: Concatenate data + push(@$constantsRef, $_) foreach (@{$class->constants}); + push(@$functionsRef, $_) foreach (@{$class->functions}); + push(@$attributesRef, $_) foreach (@{$class->attributes}); + } + } else { + die("Could NOT find specified parent interface \"$interface\"!\n"); + } + } +} + +# Append an attribute to an array if its name does not exist in the array. +sub AppendAttribute +{ + my $attributes = shift; + my $newAttr = shift; + foreach (@$attributes) { + if ($_->signature->name eq $newAttr->signature->name) { + print " | |> -> $newAttr->signature->name is overridden.\n | |>\n" if $verbose; + return; + } + } + push(@$attributes, $newAttr); +} + +# Helpers for all CodeGenerator***.pm modules +sub IsPodType +{ + my $object = shift; + my $type = shift; + + return 1 if $podTypeHash{$type}; + return 1 if $podTypeWithWriteablePropertiesHash{$type}; + return 0; +} + +sub IsPodTypeWithWriteableProperties +{ + my $object = shift; + my $type = shift; + + return 1 if $podTypeWithWriteablePropertiesHash{$type}; + return 0; +} + +sub IsPrimitiveType +{ + my $object = shift; + my $type = shift; + + return 1 if $primitiveTypeHash{$type}; + return 0; +} + +sub IsStringType +{ + my $object = shift; + my $type = shift; + + return 1 if $stringTypeHash{$type}; + return 0; +} + +sub IsNonPointerType +{ + my $object = shift; + my $type = shift; + + return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type}; + return 0; +} + +sub IsSVGAnimatedType +{ + my $object = shift; + my $type = shift; + + return 1 if $svgAnimatedTypeHash{$type}; + return 0; +} + +# Internal Helper +sub ScanDirectory +{ + my $object = shift; + + my $interface = shift; + my $directory = shift; + my $useDirectory = shift; + my $reportAllFiles = shift; + + print "Scanning interface " . $interface . " in " . $directory . "\n" if $verbose; + + return if ($endCondition eq 1) and ($reportAllFiles eq 0); + + my $sourceRoot = $ENV{SOURCE_ROOT}; + my $thisDir = $sourceRoot ? "$sourceRoot/$directory" : $directory; + + opendir(DIR, $thisDir) or die "[ERROR] Can't open directory $thisDir: \"$!\"\n"; + + my @names = readdir(DIR) or die "[ERROR] Cant't read directory $thisDir \"$!\"\n"; + closedir(DIR); + + foreach my $name (@names) { + # Skip if we already found the right file or + # if we encounter 'exotic' stuff (ie. '.', '..', '.svn') + next if ($endCondition eq 1) or ($name =~ /^\./); + + # Recurisvely enter directory + if (-d "$thisDir/$name") { + $object->ScanDirectory($interface, "$directory/$name", $useDirectory, $reportAllFiles); + next; + } + + # Check wheter we found the desired file + my $condition = ($name eq $interface); + $condition = 1 if ($interface eq "allidls") and ($name =~ /\.idl$/); + + if ($condition) { + $foundFilename = "$thisDir/$name"; + + if ($reportAllFiles eq 0) { + $endCondition = 1; + } else { + push(@foundFilenames, $foundFilename); + } + } + } +} + +1; diff --git a/V8Binding/scripts/CodeGeneratorV8.pm b/V8Binding/scripts/CodeGeneratorV8.pm new file mode 100644 index 0000000..5bb69cb --- /dev/null +++ b/V8Binding/scripts/CodeGeneratorV8.pm @@ -0,0 +1,2178 @@ + +# Copyright (C) 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> +# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> +# Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com> +# Copyright (C) 2006 Alexey Proskuryakov <ap@webkit.org> +# Copyright (C) 2006 Apple Computer, Inc. +# Copyright (C) 2007 Google Inc. +# +# This file is part of the KDE project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package CodeGeneratorV8; + +use File::stat; + +my $module = ""; +my $outputDir = ""; + +my @headerContent = (); +my @implContentHeader = (); +my @implFixedHeader = (); +my @implContent = (); +my @implContentDecls = (); +my %implIncludes = (); + +my @allParents = (); + +# Default .h template +my $headerTemplate = << "EOF"; +/* + This file is part of the WebKit open source project. + This file has been generated by generate-bindings.pl. DO NOT MODIFY! + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +EOF + +# Default constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $codeGenerator = shift; + $outputDir = shift; + + bless($reference, $object); + return $reference; +} + +sub finish +{ + my $object = shift; + + # Commit changes! + $object->WriteData(); +} + +sub leftShift($$) { + my ($value, $distance) = @_; + return (($value << $distance) & 0xFFFFFFFF); +} + +# Uppercase the first letter, while respecting WebKit style guidelines. +# E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang. +sub WK_ucfirst +{ + my $param = shift; + my $ret = ucfirst($param); + $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/; + return $ret; +} + +# Lowercase the first letter while respecting WebKit style guidelines. +# URL becomes url, but SetURL becomes setURL. +sub WK_lcfirst +{ + my $param = shift; + my $ret = lcfirst($param); + $ret =~ s/uRL/url/; + return $ret; +} + +# Params: 'domClass' struct +sub GenerateInterface +{ + my $object = shift; + my $dataNode = shift; + my $defines = shift; + + # Start actual generation + $object->GenerateHeader($dataNode); + $object->GenerateImplementation($dataNode); + + my $name = $dataNode->name; + + # Open files for writing + my $headerFileName = "$outputDir/V8$name.h"; + my $implFileName = "$outputDir/V8$name.cpp"; + + open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName"; + open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName"; +} + +# Params: 'idlDocument' struct +sub GenerateModule +{ + my $object = shift; + my $dataNode = shift; + + $module = $dataNode->module; +} + +sub GetLegacyHeaderIncludes +{ + my $legacyParent = shift; + + die "Don't know what headers to include for module $module"; +} + +sub AvoidInclusionOfType +{ + my $type = shift; + + # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h / SVGMatrix.h do not exist. + return 1 if $type eq "SVGRect" or $type eq "SVGPoint" or $type eq "SVGNumber" or $type eq "SVGMatrix"; + return 0; +} + +sub UsesManualToJSImplementation +{ + my $type = shift; + + return 1 if $type eq "SVGPathSeg"; + return 0; +} + +sub AddIncludesForType +{ + my $type = $codeGenerator->StripModule(shift); + + # When we're finished with the one-file-per-class + # reorganization, we won't need these special cases. + if ($codeGenerator->IsPrimitiveType($type) or AvoidInclusionOfType($type) +# jhaas: there doesn't seem to be any harm in leaving these in +# or $type eq "DOMString" or $type eq "DOMObject" or $type eq "RGBColor" or $type eq "Rect") { + ) { + } elsif ($type =~ /SVGPathSeg/) { + $joinedName = $type; + $joinedName =~ s/Abs|Rel//; + $implIncludes{"${joinedName}.h"} = 1; + } else { + # default, include the same named file + $implIncludes{GetImplementationFileName(${type})} = 1; + } + + # additional includes (things needed to compile the bindings but not the header) + + if ($type eq "CanvasRenderingContext2D") { + $implIncludes{"CanvasGradient.h"} = 1; + $implIncludes{"CanvasPattern.h"} = 1; + $implIncludes{"CanvasStyle.h"} = 1; + } + + if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") { + $implIncludes{"PlatformString.h"} = 1; + } + + if ($type eq "CSSStyleDeclaration") { + $implIncludes{"CSSMutableStyleDeclaration.h"} = 1; + } + + if ($type eq "Plugin" or $type eq "PluginArray" or $type eq "MimeTypeArray") { + # So we can get String -> AtomicString conversion for namedItem(). + $implIncludes{"AtomicString.h"} = 1; + } +} + +sub AddIncludesForSVGAnimatedType +{ + my $type = shift; + $type =~ s/SVGAnimated//; + + if ($type eq "Point" or $type eq "Rect") { + $implIncludes{"Float$type.h"} = 1; + } elsif ($type eq "String") { + $implIncludes{"PlatformString.h"} = 1; + } + + $implIncludes{"SVGAnimatedTemplate.h"} = 1; +} + +sub AddClassForwardIfNeeded +{ + my $implClassName = shift; + + # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them! + push(@headerContent, "class $implClassName;\n\n") unless $codeGenerator->IsSVGAnimatedType($implClassName); +} + +sub GetImplementationFileName +{ + my $iface = shift; + return "HTMLCollection.h" if $iface eq "UndetectableHTMLCollection"; + return "Event.h" if $iface eq "DOMTimeStamp"; + return "NamedAttrMap.h" if $iface eq "NamedNodeMap"; + return "NameNodeList.h" if $iface eq "NodeList"; + return "XMLHttpRequest.h" if $iface eq "XMLHttpRequest"; + + return "${iface}.h"; +} + +sub GenerateHeader +{ + my $object = shift; + my $dataNode = shift; + + my $interfaceName = $dataNode->name; + my $className = "V8$interfaceName"; + my $implClassName = $interfaceName; + + # Copy contents of parent classes except the first parent or if it is + # EventTarget. + $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode); + + my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; + my $conditional = $dataNode->extendedAttributes->{"Conditional"}; + + # - Add default header template + @headerContent = split("\r", $headerTemplate); + + # - Add header protection + if ($className =~ /^V8SVG/) { + push(@headerContent, "\n#if ENABLE(SVG)\n"); + } elsif (IsVideoClassName($className)) { + push(@headerContent, "\n#if ENABLE(VIDEO)\n"); + } elsif (IsWorkerClassName($className)) { + push(@headerContent, "\n#if ENABLE(WORKERS)\n"); + } + + push(@headerContent, "\n#ifndef $className" . "_H"); + push(@headerContent, "\n#define $className" . "_H\n\n"); + + # Get correct pass/store types respecting PODType flag + my $podType = $dataNode->extendedAttributes->{"PODType"}; + my $passType = $podType ? "JSSVGPODTypeWrapper<$podType>*" : "$implClassName*"; + + push(@headerContent, "#include \"$podType.h\"\n") if $podType and ($podType ne "double" and $podType ne "float" and $podType ne "RGBA32"); + + push(@headerContent, "#include <v8.h>\n"); + push(@headerContent, "#include <wtf/HashMap.h>\n"); + push(@headerContent, "#include \"StringHash.h\"\n"); + + push(@headerContent, "\nnamespace WebCore {\n\n"); + push(@headerContent, "class V8ClassIndex;\n"); + push(@headerContent, "\nclass $className {\n"); + push(@headerContent, <<END); + + public: + static bool HasInstance(v8::Handle<v8::Value> value); + static v8::Persistent<v8::FunctionTemplate> GetRawTemplate(); +END + + if ($implClassName eq "DOMWindow") { + push(@headerContent, <<END); + static v8::Persistent<v8::ObjectTemplate> GetShadowObjectTemplate(); +END + } + + push(@headerContent, <<END); + + private: + static v8::Persistent<v8::FunctionTemplate> GetTemplate(); + + friend class V8ClassIndex; +}; + +END + + push(@headerContent, "}\n\n"); + push(@headerContent, "#endif // $className" . "_H\n"); + + if ($className =~ /^V8SVG/) { + push(@headerContent, "\n#endif // ENABLE(SVG)\n"); + } elsif (IsVideoClassName($className)) { + push(@headerContent, "\n#endif // ENABLE(VIDEO)\n"); + } elsif (IsWorkerClassName($className)) { + push(@headerContent, "\n#endif // ENABLE(WORKERS)\n"); + } +} + + +sub GenerateSetDOMException +{ + my $indent = shift; + my $result = ""; + + $result .= $indent . "if (ec) {\n"; + $result .= $indent . " V8Proxy::SetDOMException(ec);\n"; + $result .= $indent . " return v8::Handle<v8::Value>();\n"; + $result .= $indent . "}\n"; + + return $result; +} + +sub IsNodeSubType +{ + my $dataNode = shift; + return 1 if ($dataNode->name eq "Node"); + foreach (@allParents) { + my $parent = $codeGenerator->StripModule($_); + return 1 if $parent eq "Node"; + } + return 0; +} + +sub HolderToNative +{ + my $dataNode = shift; + my $implClassName = shift; + my $classIndex = shift; + + if (IsNodeSubType($dataNode)) { + push(@implContentDecls, <<END); + $implClassName* imp = V8Proxy::DOMWrapperToNode<$implClassName>(holder); +END + + } else { + push(@implContentDecls, <<END); + $implClassName* imp = V8Proxy::ToNativeObject<$implClassName>(V8ClassIndex::$classIndex, holder); +END + + } +} + +sub GenerateDomainSafeFunctionGetter +{ + my $function = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $className = "V8" . $dataNode->name; + my $funcName = $function->signature->name; + + my $signature = "v8::Signature::New(" . $className . "::GetRawTemplate())"; + if ($function->signature->extendedAttributes->{"V8DoNotCheckSignature"}) { + $signature = "v8::Local<v8::Signature>()"; + } + + my $newTemplateString = GenerateNewFunctionTemplate($function, $dataNode, $signature); + + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, <<END); + static v8::Handle<v8::Value> ${funcName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { + INC_STATS(\"DOM.$implClassName.$funcName._get\"); + static v8::Persistent<v8::FunctionTemplate> private_template = + v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); + if (holder.IsEmpty()) { + // can only reach here by 'object.__proto__.func', and it should passed + // domain security check already + + return private_template->GetFunction(); + } +END + + HolderToNative($dataNode, $implClassName, $classIndex); + + push(@implContentDecls, <<END); + if (!V8Proxy::CanAccessFrame(imp->frame(), false)) { + static v8::Persistent<v8::FunctionTemplate> shared_template = + v8::Persistent<v8::FunctionTemplate>::New($newTemplateString); + return shared_template->GetFunction(); + + } else { + return private_template->GetFunction(); + } + } + +END +} + +sub GenerateConstructorGetter +{ + my $implClassName = shift; + my $classIndex = shift; + + push(@implContentDecls, <<END); + static v8::Handle<v8::Value> ${implClassName}ConstructorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { + INC_STATS(\"DOM.$implClassName.constructors._get\"); + v8::Handle<v8::Value> data = info.Data(); + ASSERT(data->IsNumber()); + V8ClassIndex::V8WrapperType type = V8ClassIndex::FromInt(data->Int32Value()); +END + + if ($classIndex eq "DOMWINDOW") { + push(@implContentDecls, <<END); + DOMWindow* window = V8Proxy::ToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, info.Holder()); + Frame* frame = window->frame(); + if (frame) { + // Get the proxy corresponding to the DOMWindow if possible to + // make sure that the constructor function is constructed in the + // context of the DOMWindow and not in the context of the caller. + return V8Proxy::retrieve(frame)->GetConstructor(type); + } +END + } + + if ($classIndex eq "WORKERCONTEXT") { + $implIncludes{"WorkerContextExecutionProxy.h"} = 1; + push(@implContentDecls, <<END); + return WorkerContextExecutionProxy::retrieve()->GetConstructor(type); +END + } else { + push(@implContentDecls, " return V8Proxy::retrieve()->GetConstructor(type);"); + } + + push(@implContentDecls, <<END); + } + +END +} + +sub GenerateNormalAttrGetter +{ + my $attribute = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $attrExt = $attribute->signature->extendedAttributes; + + my $attrName = $attribute->signature->name; + $implIncludes{"v8_proxy.h"} = 1; + + my $attrType = $codeGenerator->StripModule($attribute->signature->type); + my $attrIsPodType = $codeGenerator->IsPodType($attrType); + my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); + my $isPodType = $codeGenerator->IsPodType($implClassName); + my $skipContext = 0; + + + if ($isPodType) { + $implClassName = GetNativeType($implClassName); + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + } + + # Special case: SVGZoomEvent's attributes are all read-only + if ($implClassName eq "SVGZoomEvent") { + $attrIsPodType = 0; + $skipContext = 1; + } + + # Special case: SVGSVGEelement::viewport is read-only + if (($implClassName eq "SVGSVGElement") and ($attrName eq "viewport")) { + $attrIsPodType = 0; + $skipContext = 1; + } + + # Special case for SVGColor + if (($implClassName eq "SVGColor") and ($attrName eq "rgbColor")) { + $attrIsPodType = 0; + } + + my $getterStringUsesImp = $implClassName ne "double"; + + # Getter + push(@implContentDecls, <<END); + static v8::Handle<v8::Value> ${attrName}AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { + INC_STATS(\"DOM.$implClassName.$attrName._get\"); +END + + if ($isPodType) { + push(@implContentDecls, <<END); + V8SVGPODTypeWrapper<$implClassName>* imp_wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder()); + $implClassName imp_instance = *imp_wrapper; +END + if ($getterStringUsesImp) { + push(@implContentDecls, <<END); + $implClassName* imp = &imp_instance; +END + } + + } elsif ($attrExt->{"v8OnProto"} || $attrExt->{"V8DisallowShadowing"}) { + # perform lookup first + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); + if (holder.IsEmpty()) return v8::Undefined(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } else { + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = info.Holder(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } + + # Generate security checks if necessary + if ($attribute->signature->extendedAttributes->{"CheckNodeSecurity"}) { + push(@implContentDecls, " if (!V8Proxy::CheckNodeSecurity(imp->$attrName())) return v8::Undefined();\n\n"); + } elsif ($attribute->signature->extendedAttributes->{"CheckFrameSecurity"}) { + push(@implContentDecls, " if (!V8Proxy::CheckNodeSecurity(imp->contentDocument())) return v8::Undefined();\n\n"); + } + + my $useExceptions = 1 if @{$attribute->getterExceptions} and !($isPodType); + if ($useExceptions) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, " ExceptionCode ec = 0;\n"); + } + + if ($attribute->signature->extendedAttributes->{"v8referenceattr"}) { + $attrName = $attribute->signature->extendedAttributes->{"v8referenceattr"}; + } + + my $getterFunc = WK_lcfirst($attrName); + $getterFunc .= "Animated" if $codeGenerator->IsSVGAnimatedType($attribute->signature->type); + + my $returnType = $codeGenerator->StripModule($attribute->signature->type); + + my $getterString; + if ($getterStringUsesImp) { + $getterString = "imp->$getterFunc("; + $getterString .= "ec" if $useExceptions; + $getterString .= ")"; + if (IsRefPtrType($returnType)) { + $implIncludes{"wtf/GetPtr.h"} = 1; + $getterString = "WTF::getPtr(" . $getterString . ")"; + } + if ($nativeType eq "int" and + $attribute->signature->extendedAttributes->{"ConvertFromString"}) { + $getterString .= ".toInt()"; + } + } else { + $getterString = "imp_instance"; + } + if ($nativeType eq "String") { + $getterString = "ToString($getterString)"; + } + + my $result; + my $wrapper; + + if ($attrIsPodType) { + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + + my $getter = $getterString; + $getter =~ s/imp->//; + $getter =~ s/\(\)//; + my $setter = "set" . WK_ucfirst($getter); + + my $implClassIsAnimatedType = $codeGenerator->IsSVGAnimatedType($implClassName); + if (not $implClassIsAnimatedType + and $codeGenerator->IsPodTypeWithWriteableProperties($attrType) + and not defined $attribute->signature->extendedAttributes->{"Immutable"}) { + if ($codeGenerator->IsPodType($implClassName)) { + $wrapper = "new V8SVGStaticPODTypeWrapperWithPODTypeParent<$nativeType, $implClassName>($getterString, imp_wrapper)"; + } else { + $wrapper = "new V8SVGStaticPODTypeWrapperWithParent<$nativeType, $implClassName>(imp, &${implClassName}::$getter, &${implClassName}::$setter)"; + } + } else { + if ($implClassIsAnimatedType) { + $wrapper = "V8SVGDynamicPODTypeWrapperCache<$nativeType, $implClassName>::lookupOrCreateWrapper(imp, &${implClassName}::$getter, &${implClassName}::$setter)"; + } else { + $wrapper = GenerateSVGStaticPodTypeWrapper($returnType, $getterString); + } + } + + push(@implContentDecls, " void* wrapper = $wrapper;\n"); + } elsif ($nativeType ne "RGBColor") { + push(@implContentDecls, " $nativeType v = "); + + push(@implContentDecls, "$getterString;\n"); + + if ($useExceptions) { + push(@implContentDecls, GenerateSetDOMException(" ")); + } + + $result = "v"; + if (IsRefPtrType($returnType)) { + $result = "WTF::getPtr(" . $result . ")"; + } + } else { + # Special case: RGBColor is noncopyable + $result = $getterString; + } + + + if (IsSVGTypeNeedingContextParameter($attrType) && !$skipContext) { + my $resultObject = $result; + if ($attrIsPodType) { + $resultObject = "wrapper"; + } + + push(@implContentDecls, GenerateSVGContextAssignment($implClassName, $resultObject, " ")); + } + + if ($attrIsPodType) { + my $classIndex = uc($attrType); + push(@implContentDecls, " return V8Proxy::ToV8Object(V8ClassIndex::$classIndex, wrapper);\n"); + } else { + push(@implContentDecls, " return " . NativeToJSValue($attribute->signature, $result). ";\n"); + } + + push(@implContentDecls, " }\n\n"); # end of getter +} + + +sub GenerateReplaceableAttrSetter +{ + my $implClassName = shift; + + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, + " static void ${attrName}AttrSetter(v8::Local<v8::String> name," . + " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n"); + + push(@implContentDecls, " INC_STATS(\"DOM.$implClassName.$attrName._set\");\n"); + + push(@implContentDecls, " v8::Local<v8::String> ${attrName}_string = v8::String::New(\"${attrName}\");\n"); + push(@implContentDecls, " info.Holder()->Delete(${attrName}_string);\n"); + push(@implContentDecls, " info.This()->Set(${attrName}_string, value);\n"); + push(@implContentDecls, " }\n\n"); +} + + +sub GenerateNormalAttrSetter +{ + my $attribute = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $attrExt = $attribute->signature->extendedAttributes; + + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, + " static void ${attrName}AttrSetter(v8::Local<v8::String> name," . + " v8::Local<v8::Value> value, const v8::AccessorInfo& info) {\n"); + + push(@implContentDecls, " INC_STATS(\"DOM.$implClassName.$attrName._set\");\n"); + + my $isPodType = $codeGenerator->IsPodType($implClassName); + + if ($isPodType) { + $implClassName = GetNativeType($implClassName); + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + push(@implContentDecls, " V8SVGPODTypeWrapper<$implClassName>* wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$implClassName> >(V8ClassIndex::$classIndex, info.Holder());\n"); + push(@implContentDecls, " $implClassName imp_instance = *wrapper;\n"); + push(@implContentDecls, " $implClassName* imp = &imp_instance;\n"); + + } elsif ($attrExt->{"v8OnProto"}) { + # perform lookup first + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = V8Proxy::LookupDOMWrapper(V8ClassIndex::$classIndex, info.This()); + if (holder.IsEmpty()) return v8::Undefined(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } else { + push(@implContentDecls, <<END); + v8::Handle<v8::Object> holder = info.Holder(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } + + my $nativeType = GetNativeTypeFromSignature($attribute->signature, 0); + push(@implContentDecls, " $nativeType v = " . JSValueToNative($attribute->signature, "value") . ";\n"); + + my $result = ""; + if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { + $result .= "WebCore::String::number("; + } + $result .= "v"; + if ($nativeType eq "int" and $attribute->signature->extendedAttributes->{"ConvertFromString"}) { + $result .= ")"; + } + my $returnType = $codeGenerator->StripModule($attribute->signature->type); + if (IsRefPtrType($returnType)) { + $result = "WTF::getPtr(" . $result . ")"; + } + + my $useExceptions = 1 if @{$attribute->setterExceptions} and !($isPodType); + + if ($useExceptions) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, " ExceptionCode ec = 0;\n"); + } + + if ($implClassName eq "double") { + push(@implContentDecls, " *imp = $result;\n"); + } else { + push(@implContentDecls, " imp->set" . WK_ucfirst($attrName) . "(" . $result); + push(@implContentDecls, ", ec") if $useExceptions; + push(@implContentDecls, ");\n"); + } + + if ($useExceptions) { + push(@implContentDecls, " V8Proxy::SetDOMException(ec);\n"); + } + + if ($isPodType) { + push(@implContentDecls, " wrapper->commitChange(*imp, V8Proxy::GetSVGContext(wrapper));\n"); + } elsif (IsSVGTypeNeedingContextParameter($implClassName)) { + $implIncludes{"SVGElement.h"} = 1; + + my $currentObject = "imp"; + if ($isPodType) { + $currentObject = "wrapper"; + } + + push(@implContentDecls, " if (SVGElement* context = V8Proxy::GetSVGContext($currentObject)) {\n"); + push(@implContentDecls, " context->svgAttributeChanged(imp->associatedAttributeName());\n"); + push(@implContentDecls, " }\n"); + } + + push(@implContentDecls, " return;\n"); + push(@implContentDecls, " }\n\n"); # end of setter +} + + +sub GenerateNewFunctionTemplate +{ + $function = shift; + $dataNode = shift; + $signature = shift; + + my $interfaceName = $dataNode->name; + my $name = $function->signature->name; + + if ($function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}) { + if ($function->signature->extendedAttributes->{"Custom"} && + $function->signature->extendedAttributes->{"V8Custom"}) { + die "Custom and V8Custom should be mutually exclusive!" + } + my $customFunc = $function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}; + if ($customFunc eq 1) { + $customFunc = $interfaceName . WK_ucfirst($name); + } + return "v8::FunctionTemplate::New(V8Custom::v8${customFunc}Callback, v8::Handle<v8::Value>(), $signature)"; + } else { + return "v8::FunctionTemplate::New(${interfaceName}Internal::${name}Callback, v8::Handle<v8::Value>(), $signature)"; + } +} + + +sub GenerateFunctionCallback +{ + my $function = shift; + my $dataNode = shift; + my $classIndex = shift; + my $implClassName = shift; + + my $interfaceName = $dataNode->name; + my $name = $function->signature->name; + + push(@implContentDecls, +" static v8::Handle<v8::Value> ${name}Callback(const v8::Arguments& args) {\n" . +" INC_STATS(\"DOM.$implClassName.$name\");\n"); + + my $numParameters = @{$function->parameters}; + + if ($function->signature->extendedAttributes->{"RequiresAllArguments"}) { + push(@implContentDecls, + " if (args.Length() < $numParameters) return v8::Undefined();\n"); + } + + if ($codeGenerator->IsPodType($implClassName)) { + my $nativeClassName = GetNativeType($implClassName); + push(@implContentDecls, " V8SVGPODTypeWrapper<$nativeClassName>* imp_wrapper = V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<$nativeClassName> >(V8ClassIndex::$classIndex, args.Holder());\n"); + push(@implContentDecls, " $nativeClassName imp_instance = *imp_wrapper;\n"); + push(@implContentDecls, " $nativeClassName* imp = &imp_instance;\n"); + } else { + push(@implContentDecls, <<END); + v8::Handle<v8::Value> holder = args.Holder(); +END + HolderToNative($dataNode, $implClassName, $classIndex); + } + + # Check domain security if needed + if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} + || $interfaceName eq "DOMWindow") + && !$function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}) { + # We have not find real use cases yet. + push(@implContentDecls, +" if (!V8Proxy::CanAccessFrame(imp->frame(), true)) {\n". +" return v8::Undefined();\n" . +" }\n"); + } + + + if (@{$function->raisesExceptions}) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, " ExceptionCode ec = 0;\n"); + } + + if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { + push(@implContentDecls, " ScriptCallStack callStack(args, $numParameters);\n"); + $implIncludes{"ScriptCallStack.h"} = 1; + } + + my $paramIndex = 0; + foreach my $parameter (@{$function->parameters}) { + TranslateParameter($parameter); + + my $parameterName = $parameter->name; + + if ($parameter->extendedAttributes->{"Optional"}) { + # Generate early call if there are not enough parameters. + push(@implContentDecls, " if (args.Length() <= $paramIndex) {\n"); + my $functionCall = GenerateFunctionCallString($function, $paramIndex, " " x 2, $implClassName); + push(@implContentDecls, $functionCall); + push(@implContentDecls, " }\n"); + } + + if (BasicTypeCanFailConversion($parameter)) { + push(@implContentDecls, " bool ${parameterName}Ok;\n"); + } + + push(@implContentDecls, " " . GetNativeTypeFromSignature($parameter, 1) . " $parameterName = "); + push(@implContentDecls, JSValueToNative($parameter, "args[$paramIndex]", + BasicTypeCanFailConversion($parameter) ? "${parameterName}Ok" : undef) . ";\n"); + + if (TypeCanFailConversion($parameter)) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, +" if (!$parameterName" . (BasicTypeCanFailConversion($parameter) ? "Ok" : "") . ") {\n" . +" V8Proxy::SetDOMException(TYPE_MISMATCH_ERR);\n" . +" return v8::Handle<v8::Value>();\n" . +" }\n"); + } + + if ($parameter->extendedAttributes->{"IsIndex"}) { + $implIncludes{"ExceptionCode.h"} = 1; + push(@implContentDecls, +" if ($parameterName < 0) {\n" . +" V8Proxy::SetDOMException(INDEX_SIZE_ERR);\n" . +" return v8::Handle<v8::Value>();\n" . +" }\n"); + } + + $paramIndex++; + } + + # Build the function call string. + my $callString = GenerateFunctionCallString($function, $paramIndex, " ", $implClassName); + push(@implContentDecls, "$callString"); + push(@implContentDecls, " }\n\n"); +} + + +sub GenerateBatchedAttributeData +{ + my $interfaceName = shift; + my $attributes = shift; + + foreach my $attribute (@$attributes) { + my $attrName = $attribute->signature->name; + my $attrExt = $attribute->signature->extendedAttributes; + + my $accessControl = "v8::DEFAULT"; + if ($attrExt->{"DoNotCheckDomainSecurityOnGet"}) { + $accessControl = "v8::ALL_CAN_READ"; + } elsif ($attrExt->{"DoNotCheckDomainSecurityOnSet"}) { + $accessControl = "v8::ALL_CAN_WRITE"; + } elsif ($attrExt->{"DoNotCheckDomainSecurity"}) { + $accessControl = "v8::ALL_CAN_READ"; + if (!($attribute->type =~ /^readonly/) && !($attrExt->{"V8ReadOnly"})) { + $accessControl .= "|v8::ALL_CAN_WRITE"; + } + } + if ($attrExt->{"V8DisallowShadowing"}) { + $accessControl .= "|v8::PROHIBITS_OVERWRITING"; + } + $accessControl = "static_cast<v8::AccessControl>(" . $accessControl . ")"; + + + my $customAccessor = + $attrExt->{"Custom"} || + $attrExt->{"CustomSetter"} || + $attrExt->{"CustomGetter"} || + $attrExt->{"V8Custom"} || + $attrExt->{"V8CustomSetter"} || + $attrExt->{"V8CustomGetter"} || + ""; + if ($customAccessor eq 1) { + # use the naming convension, interface + (capitalize) attr name + $customAccessor = $interfaceName . WK_ucfirst($attrName); + } + + my $getter; + my $setter; + my $propAttr = "v8::None"; + + # Check attributes. + if ($attrExt->{"DontEnum"}) { + $propAttr .= "|v8::DontEnum"; + } + if ($attrExt->{"V8DisallowShadowing"}) { + $propAttr .= "|v8::DontDelete"; + } + + my $on_proto = "0 /* on instance */"; + my $data = "V8ClassIndex::INVALID_CLASS_INDEX /* no data */"; + + # Constructor + if ($attribute->signature->type =~ /Constructor$/) { + my $constructorType = $codeGenerator->StripModule($attribute->signature->type); + $constructorType =~ s/Constructor$//; + my $constructorIndex = uc($constructorType); + $data = "V8ClassIndex::${constructorIndex}"; + $getter = "${interfaceName}Internal::${interfaceName}ConstructorGetter"; + $setter = "0"; + $propAttr = "v8::ReadOnly"; + + # EventListeners + } elsif ($attrExt->{"ProtectedListener"}) { + if ($interfaceName eq "DOMWindow") { + $getter = "V8Custom::v8DOMWindowEventHandlerAccessorGetter"; + $setter = "V8Custom::v8DOMWindowEventHandlerAccessorSetter"; + } else { + $getter = "V8Custom::v8ElementEventHandlerAccessorGetter"; + $setter = "V8Custom::v8ElementEventHandlerAccessorSetter"; + } + + # Custom Getter and Setter + } elsif ($attrExt->{"Custom"} || $attrExt->{"V8Custom"}) { + $getter = "V8Custom::v8${customAccessor}AccessorGetter"; + if ($interfaceName eq "WorkerContext" and $attrName eq "self") { + $setter = "0"; + $propAttr = "v8::ReadOnly"; + } else { + $setter = "V8Custom::v8${customAccessor}AccessorSetter"; + } + + # Custom Setter + } elsif ($attrExt->{"CustomSetter"} || $attrExt->{"V8CustomSetter"}) { + $getter = "${interfaceName}Internal::${attrName}AttrGetter"; + $setter = "V8Custom::v8${customAccessor}AccessorSetter"; + + # Custom Getter + } elsif ($attrExt->{"CustomGetter"}) { + $getter = "V8Custom::v8${customAccessor}AccessorGetter"; + $setter = "${interfaceName}Internal::${attrName}AttrSetter"; + + # Replaceable + } elsif ($attrExt->{"Replaceable"}) { + # Replaceable accessor is put on instance template with ReadOnly attribute. + $getter = "${interfaceName}Internal::${attrName}AttrGetter"; + $setter = "0"; + $propAttr .= "|v8::ReadOnly"; + + # Normal + } else { + $getter = "${interfaceName}Internal::${attrName}AttrGetter"; + $setter = "${interfaceName}Internal::${attrName}AttrSetter"; + } + + # Read only attributes + if ($attribute->type =~ /^readonly/ || $attrExt->{"V8ReadOnly"}) { + $setter = "0"; + } + + # An accessor can be installed on the proto + if ($attrExt->{"v8OnProto"}) { + $on_proto = "1 /* on proto */"; + } + + my $commentInfo = "Attribute '$attrName' (Type: '" . $attribute->type . + "' ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; + push(@implContent, <<END); + // $commentInfo + { "$attrName", + $getter, + $setter, + $data, + $accessControl, + static_cast<v8::PropertyAttribute>($propAttr), + $on_proto }, +END + } +} + + +sub GenerateImplementation +{ + my $object = shift; + my $dataNode = shift; + my $interfaceName = $dataNode->name; + my $className = "V8$interfaceName"; + my $implClassName = $interfaceName; + my $classIndex = uc($codeGenerator->StripModule($interfaceName)); + + my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"}; + my $conditional = $dataNode->extendedAttributes->{"Conditional"}; + + @allParents = $codeGenerator->FindParentsRecursively($dataNode); + + # - Add default header template + @implContentHeader = split("\r", $headerTemplate); + + push(@implFixedHeader, + "#include \"config.h\"\n" . + "#include \"v8_proxy.h\"\n" . + "#include \"v8_binding.h\"\n\n" . + "#undef LOG\n\n"); + + if ($className =~ /^V8SVG/) { + push(@implFixedHeader, "#if ENABLE(SVG)\n\n"); + } elsif (IsVideoClassName($className)) { + push(@implFixedHeader, "#if ENABLE(VIDEO)\n\n"); + } elsif (IsWorkerClassName($className)) { + push(@implFixedHeader, "#if ENABLE(WORKERS)\n\n"); + } + + if ($className =~ /^V8SVGAnimated/) { + AddIncludesForSVGAnimatedType($interfaceName); + } + + $implIncludes{"${className}.h"} = 1; + + AddIncludesForType($interfaceName); + $implIncludes{"v8_proxy.h"} = 1; + + push(@implContentDecls, "namespace WebCore {\n"); + push(@implContentDecls, "namespace ${interfaceName}Internal {\n\n"); + push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n"); + + my $hasConstructors = 0; + + # Generate property accessors for attributes. + for ($index = 0; $index < @{$dataNode->attributes}; $index++) { + $attribute = @{$dataNode->attributes}[$index]; + $attrName = $attribute->signature->name; + $attrType = $attribute->signature->type; + + # Generate special code for the constructor attributes. + if ($attrType =~ /Constructor$/) { + $hasConstructors = 1; + next; + } + + # Make EventListeners always custom. + # TODO(mbelshe): make the perl code capable of generating the + # event setters/getters. For now, WebKit has started removing the + # [Custom] attribute, so just automatically insert it to avoid forking + # other files. This should be okay because we can't generate stubs + # for any event getter/setters anyway. + if ($attrType eq "EventListener") { + $attribute->signature->extendedAttributes->{"Custom"} = 1; + $implIncludes{"v8_custom.h"} = 1; + next; + } + + # Do not generate accessor if this is a custom attribute. The + # call will be forwarded to a hand-written accessor + # implementation. + if ($attribute->signature->extendedAttributes->{"Custom"} || + $attribute->signature->extendedAttributes->{"V8Custom"}) { + $implIncludes{"v8_custom.h"} = 1; + next; + } + + # Generate the accessor. + if ($attribute->signature->extendedAttributes->{"CustomGetter"}) { + $implIncludes{"v8_custom.h"} = 1; + } else { + GenerateNormalAttrGetter($attribute, $dataNode, $classIndex, $implClassName); + } + if ($attribute->signature->extendedAttributes->{"CustomSetter"} || + $attribute->signature->extendedAttributes->{"V8CustomSetter"}) { + $implIncludes{"v8_custom.h"} = 1; + } elsif ($attribute->signature->extendedAttributes->{"Replaceable"}) { + $dataNode->extendedAttributes->{"ExtendsDOMGlobalObject"} || die "Replaceable attribute can only be used in interface that defines ExtendsDOMGlobalObject attribute!"; +# GenerateReplaceableAttrSetter($implClassName); + } elsif ($attribute->type !~ /^readonly/ && + !$attribute->signature->extendedAttributes->{"V8ReadOnly"}) { + GenerateNormalAttrSetter($attribute, $dataNode, $classIndex, $implClassName); + } + } + + if ($hasConstructors) { + GenerateConstructorGetter($implClassName, $classIndex); + } + + # Generate methods for functions. + foreach my $function (@{$dataNode->functions}) { + # hack for addEventListener/RemoveEventListener + # TODO(fqian): avoid naming conflict + if ($function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}) { + $implIncludes{"v8_custom.h"} = 1; + + } else { + GenerateFunctionCallback($function, $dataNode, $classIndex, $implClassName); + } + + + # If the function does not need domain security check, we need to + # generate an access getter that returns different function objects + # for different calling context. + if (($dataNode->extendedAttributes->{"CheckDomainSecurity"} + || ($interfaceName eq "DOMWindow")) + && $function->signature->extendedAttributes->{"DoNotCheckDomainSecurity"}){ + GenerateDomainSafeFunctionGetter($function, $dataNode, $classIndex, $implClassName); + } + } + + # Attributes + my $attributes = $dataNode->attributes; + + # For the DOMWindow interface we partition the attributes into the + # ones that disallows shadowing and the rest. + my @disallows_shadowing; + my @normal; + if ($interfaceName eq "DOMWindow") { + foreach my $attribute (@$attributes) { + if ($attribute->signature->extendedAttributes->{"V8DisallowShadowing"}) { + push(@disallows_shadowing, $attribute); + } else { + push(@normal, $attribute); + } + } + # Put the attributes that disallow shadowing on the shadow object. + $attributes = \@normal; + push(@implContent, "static const BatchedAttribute shadow_attrs[] = {\n"); + GenerateBatchedAttributeData($interfaceName, \@disallows_shadowing); + push(@implContent, "};\n"); + + } + + my $has_attributes = 0; + if (@$attributes) { + $has_attributes = 1; + push(@implContent, "static const BatchedAttribute attrs[] = {\n"); + GenerateBatchedAttributeData($interfaceName, $attributes); + push(@implContent, "};\n"); + } + + # Setup constants + my $has_constants = 0; + if (@{$dataNode->constants}) { + $has_constants = 1; + push(@implContent, "static const BatchedConstant consts[] = {\n"); + } + foreach my $constant (@{$dataNode->constants}) { + my $name = $constant->name; + my $value = $constant->value; + # TODO we need the static_cast here only because of one constant, NodeFilter.idl + # defines "const unsigned long SHOW_ALL = 0xFFFFFFFF". It would be better if we + # handled this here, and converted it to a -1 constant in the c++ output. + push(@implContent, <<END); + { "${name}", static_cast<signed int>($value) }, +END + } + if ($has_constants) { + push(@implContent, "};\n"); + } + + push(@implContentDecls, "} // namespace ${interfaceName}Internal\n\n"); + + my $access_check = "/* no access check */"; + if ($dataNode->extendedAttributes->{"CheckDomainSecurity"} && + !($interfaceName eq "DOMWindow")) { + $access_check = "instance->SetAccessCheckCallbacks(V8Custom::v8${interfaceName}NamedSecurityCheck, V8Custom::v8${interfaceName}IndexedSecurityCheck, v8::Integer::New(V8ClassIndex::ToInt(V8ClassIndex::${classIndex})));"; + } + + # For the DOMWindow interface, generate the shadow object template + # configuration method. + if ($implClassName eq "DOMWindow") { + push(@implContent, <<END); +static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Persistent<v8::ObjectTemplate> templ) { + BatchConfigureAttributes(templ, + v8::Handle<v8::ObjectTemplate>(), + shadow_attrs, + sizeof(shadow_attrs)/sizeof(*shadow_attrs)); + return templ; +} +END + } + + # Generate the template configuration method + push(@implContent, <<END); +static v8::Persistent<v8::FunctionTemplate> Configure${className}Template(v8::Persistent<v8::FunctionTemplate> desc) { + v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate(); + instance->SetInternalFieldCount(2); + v8::Local<v8::Signature> default_signature = v8::Signature::New(desc); + v8::Local<v8::ObjectTemplate> proto = desc->PrototypeTemplate(); + $access_check +END + + + # Set up our attributes if we have them + if ($has_attributes) { + push(@implContent, <<END); + BatchConfigureAttributes(instance, proto, attrs, sizeof(attrs)/sizeof(*attrs)); +END + } + + # Define our functions with Set() or SetAccessor() + foreach my $function (@{$dataNode->functions}) { + my $attrExt = $function->signature->extendedAttributes; + my $name = $function->signature->name; + + my $property_attributes = "v8::DontDelete"; + if ($attrExt->{"DontEnum"}) { + $property_attributes .= "|v8::DontEnum"; + } + if ($attrExt->{"V8ReadOnly"}) { + $property_attributes .= "|v8::ReadOnly"; + } + + my $commentInfo = "Function '$name' (ExtAttr: '" . join(' ', keys(%{$attrExt})) . "')"; + + my $template = "proto"; + if ($attrExt->{"V8OnInstance"}) { + $template = "instance"; + } + + if ($attrExt->{"DoNotCheckDomainSecurity"} && + ($dataNode->extendedAttributes->{"CheckDomainSecurity"} || $interfaceName eq "DOMWindow")) { + # Mark the accessor as ReadOnly and set it on the proto object so + # it can be shadowed. This is really a hack to make it work. + # There are several sceneria to call into the accessor: + # 1) from the same domain: "window.open": + # the accessor finds the DOM wrapper in the proto chain; + # 2) from the same domain: "window.__proto__.open": + # the accessor will NOT find a DOM wrapper in the prototype chain + # 3) from another domain: "window.open": + # the access find the DOM wrapper in the prototype chain + # "window.__proto__.open" from another domain will fail when + # accessing '__proto__' + # + # The solution is very hacky and fragile, it really needs to be replaced + # by a better solution. + $property_attributes .= "|v8::ReadOnly"; + push(@implContent, <<END); + + // $commentInfo + $template->SetAccessor( + v8::String::New("$name"), + ${interfaceName}Internal::${name}AttrGetter, + 0, + v8::Handle<v8::Value>(), + v8::ALL_CAN_READ, + static_cast<v8::PropertyAttribute>($property_attributes)); +END + next; + } + + my $signature = "default_signature"; + if ($attrExt->{"V8DoNotCheckSignature"}){ + $signature = "v8::Local<v8::Signature>()"; + } + + if (RequiresCustomSignature($function)) { + $signature = "${name}_signature"; + push(@implContent, "\n // Custom Signature '$name'\n", CreateCustomSignature($function)); + } + + # Normal function call is a template + my $templateFunction = GenerateNewFunctionTemplate($function, $dataNode, $signature); + + + push(@implContent, <<END); + + // $commentInfo + ${template}->Set( + v8::String::New("$name"), + $templateFunction, + static_cast<v8::PropertyAttribute>($property_attributes)); +END + } + + # set the super descriptor + foreach (@{$dataNode->parents}) { + my $parent = $codeGenerator->StripModule($_); + if ($parent eq "EventTarget") { next; } + $implIncludes{"V8${parent}.h"} = 1; + my $parentClassIndex = uc($codeGenerator->StripModule($parent)); + push(@implContent, " desc->Inherit(V8Proxy::GetTemplate(V8ClassIndex::${parentClassIndex}));\n"); + last; + } + + # Set the class name. This is used when printing objects. + push(@implContent, " desc->SetClassName(v8::String::New(\"" . GetClassName(${interfaceName}) . "\"));\n"); + + if ($has_constants) { + push(@implContent, <<END); + BatchConfigureConstants(desc, proto, consts, sizeof(consts)/sizeof(*consts)); +END + } + + push(@implContent, <<END); + return desc; +} + +v8::Persistent<v8::FunctionTemplate> ${className}::GetRawTemplate() { + static v8::Persistent<v8::FunctionTemplate> ${className}_raw_cache_; + if (${className}_raw_cache_.IsEmpty()) { + v8::HandleScope scope; + v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::CheckNewLegal); + ${className}_raw_cache_ = v8::Persistent<v8::FunctionTemplate>::New(result); + } + return ${className}_raw_cache_; +} + +v8::Persistent<v8::FunctionTemplate> ${className}::GetTemplate() { + static v8::Persistent<v8::FunctionTemplate> ${className}_cache_; + if (${className}_cache_.IsEmpty()) + ${className}_cache_ = Configure${className}Template(GetRawTemplate()); + return ${className}_cache_; +} + +bool ${className}::HasInstance(v8::Handle<v8::Value> value) { + return GetRawTemplate()->HasInstance(value); +} + +END + + if ($implClassName eq "DOMWindow") { + push(@implContent, <<END); +v8::Persistent<v8::ObjectTemplate> V8DOMWindow::GetShadowObjectTemplate() { + static v8::Persistent<v8::ObjectTemplate> V8DOMWindowShadowObject_cache_; + if (V8DOMWindowShadowObject_cache_.IsEmpty()) { + V8DOMWindowShadowObject_cache_ = v8::Persistent<v8::ObjectTemplate>::New(v8::ObjectTemplate::New()); + ConfigureShadowObjectTemplate(V8DOMWindowShadowObject_cache_); + } + return V8DOMWindowShadowObject_cache_; +} +END + } + + push(@implContent, <<END); +} // namespace WebCore +END + + if ($className =~ /^V8SVG/) { + push(@implContent, "\n#endif // ENABLE(SVG)\n"); + } elsif (IsVideoClassName($className)) { + push(@implContent, "\n#endif // ENABLE(VIDEO)\n"); + } elsif (IsWorkerClassName($className)) { + push(@implContent, "\n#endif // ENABLE(WORKERS)\n"); + } +} + + +sub GenerateFunctionCallString() +{ + my $function = shift; + my $numberOfParameters = shift; + my $indent = shift; + my $implClassName = shift; + + my $name = $function->signature->name; + my $isPodType = $codeGenerator->IsPodType($implClassName); + my $returnType = $codeGenerator->StripModule($function->signature->type); + my $returnsPodType = $codeGenerator->IsPodType($returnType); + my $nativeReturnType = GetNativeType($returnType, 0); + my $result = ""; + + # Special case: SVG matrix transform methods should not mutate + # the matrix but return a copy + my $copyFirst = 0; + if ($implClassName eq "SVGMatrix" && $function->signature->type eq "SVGMatrix") { + $copyFirst = 1; + } + + if ($function->signature->extendedAttributes->{"v8implname"}) { + $name = $function->signature->extendedAttributes->{"v8implname"}; + } + + if ($function->signature->extendedAttributes->{"ImplementationFunction"}) { + $name = $function->signature->extendedAttributes->{"ImplementationFunction"}; + } + + my $functionString = "imp->${name}("; + + if ($copyFirst) { + $functionString = "result.${name}("; + } + + my $returnsListItemPodType = 0; + # SVG lists functions that return POD types require special handling + if (IsSVGListTypeNeedingSpecialHandling($implClassName) && IsSVGListMethod($name) && $returnsPodType) { + $returnsListItemPodType = 1; + $result .= $indent . "SVGList<RefPtr<SVGPODListItem<$nativeReturnType> > >* listImp = imp;\n"; + $functionString = "listImp->${name}("; + } + + my $first = 1; + my $index = 0; + my $nodeToReturn = 0; + + foreach my $parameter (@{$function->parameters}) { + if ($index eq $numberOfParameters) { + last; + } + if ($first) { $first = 0; } + else { $functionString .= ", "; } + my $paramName = $parameter->name; + my $paramType = $parameter->type; + + # This is a bit of a hack... we need to convert parameters to methods on SVG lists + # of POD types which are items in the list to appropriate SVGList<> instances + if ($returnsListItemPodType && $paramType . "List" eq $implClassName) { + $paramName = "SVGPODListItem<" . GetNativeType($paramType, 1) . ">::copy($paramName)"; + } + + if ($parameter->type eq "NodeFilter") { + $functionString .= "$paramName.get()"; + } else { + $functionString .= $paramName; + } + + if ($parameter->extendedAttributes->{"Return"}) { + $nodeToReturn = $parameter->name; + } + $index++; + } + + if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) { + $functionString .= ", " if not $first; + $functionString .= "&callStack"; + if ($first) { $first = 0; } + } + + if (@{$function->raisesExceptions}) { + $functionString .= ", " if not $first; + $functionString .= "ec"; + } + $functionString .= ")"; + + if ((IsRefPtrType($returnType) || $returnsListItemPodType) && + !$nodeToReturn) { + # We don't use getPtr when $nodeToReturn because that situation is + # special-cased below to return a bool. + $implIncludes{"wtf/GetPtr.h"} = 1; + $functionString = "WTF::getPtr(" . $functionString . ")"; + } + + if ($nodeToReturn) { + # Special case for insertBefore, replaceChild, removeChild and + # appendChild functions from Node. + $result .= $indent . "bool success = $functionString;\n"; + if (@{$function->raisesExceptions}) { + $result .= GenerateSetDOMException($indent); + } + $result .= $indent . "if (success)\n"; + $result .= $indent . " " . + "return V8Proxy::NodeToV8Object($nodeToReturn);\n"; + $result .= $indent . "return v8::Null();\n"; + return $result; + } elsif ($returnType eq "void") { + $result .= $indent . "$functionString;\n"; + } elsif ($copyFirst) { + $result .= + $indent . GetNativeType($returnType, 0) . " result = *imp;\n" . + $indent . "$functionString;\n"; + } elsif ($returnsListItemPodType) { + $result .= $indent . "RefPtr<SVGPODListItem<$nativeReturnType> > result = $functionString;\n"; + } else { + $result .= $indent . $nativeReturnType . " result = $functionString;\n"; + } + + if (@{$function->raisesExceptions}) { + $result .= GenerateSetDOMException($indent); + } + + my $return = "result"; + if (IsRefPtrType($returnType) || $returnsListItemPodType) { + $implIncludes{"wtf/GetPtr.h"} = 1; + $return = "WTF::getPtr(" . $return . ")"; + } + + # If the return type is a POD type, separate out the wrapper generation + if ($returnsListItemPodType) { + $result .= $indent . "V8SVGPODTypeWrapper<" . $nativeReturnType . ">* wrapper = new "; + $result .= "V8SVGPODTypeWrapperCreatorForList<" . $nativeReturnType . ">($return, imp->associatedAttributeName());\n"; + $return = "wrapper"; + } elsif ($returnsPodType) { + $result .= $indent . "V8SVGPODTypeWrapper<" . $nativeReturnType . ">* wrapper = "; + $result .= GenerateSVGStaticPodTypeWrapper($returnType, $return) . ";\n"; + $return = "wrapper"; + } + + my $generatedSVGContextRetrieval = 0; + # If the return type needs an SVG context, output it + if (IsSVGTypeNeedingContextParameter($returnType)) { + $result .= GenerateSVGContextAssignment($implClassName, $return, $indent); + $generatedSVGContextRetrieval = 1; + } + + if (IsSVGTypeNeedingContextParameter($implClassName) && $implClassName =~ /List$/ && IsSVGListMutator($name)) { + if (!$generatedSVGContextRetrieval) { + $result .= GenerateSVGContextRetrieval($implClassName, $indent); + $generatedSVGContextRetrieval = 1; + } + + $result .= $indent . "context->svgAttributeChanged(imp->associatedAttributeName());\n"; + $implIncludes{"SVGElement.h"} = 1; + } + + # If the implementing class is a POD type, commit changes + if ($isPodType) { + if (!$generatedSVGContextRetrieval) { + $result .= GenerateSVGContextRetrieval($implClassName, $indent); + $generatedSVGContextRetrieval = 1; + } + + $result .= $indent . "imp_wrapper->commitChange(imp_instance, context);\n"; + } + + if ($returnsPodType) { + my $classIndex = uc($returnType); + $result .= $indent . "return V8Proxy::ToV8Object(V8ClassIndex::$classIndex, wrapper);\n"; + } else { + $result .= $indent . "return " . NativeToJSValue($function->signature, $return) . ";\n"; + } + + return $result; +} + + +# Get the class name used for printing javascript DOM-object wrappers. +sub GetClassName +{ + my $type = shift; + return "HTMLCollection" if $type eq "UndetectableHTMLCollection"; + return $type; +} + + +sub GetNativeTypeFromSignature +{ + my $signature = shift; + my $isParameter = shift; + + my $type = $codeGenerator->StripModule($signature->type); + + return GetNativeType($type, $isParameter); +} + +sub IsRefPtrType +{ + my $type = shift; + return 1 if $type eq "Attr"; + return 1 if $type eq "CanvasGradient"; + return 1 if $type eq "ClientRect"; + return 1 if $type eq "ClientRectList"; + return 1 if $type eq "CDATASection"; + return 1 if $type eq "Comment"; + return 1 if $type eq "CSSRule"; + return 1 if $type eq "CSSStyleRule"; + return 1 if $type eq "CSSCharsetRule"; + return 1 if $type eq "CSSImportRule"; + return 1 if $type eq "CSSMediaRule"; + return 1 if $type eq "CSSFontFaceRule"; + return 1 if $type eq "CSSPageRule"; + return 1 if $type eq "CSSPrimitiveValue"; + return 1 if $type eq "CSSStyleSheet"; + return 1 if $type eq "CSSStyleDeclaration"; + return 1 if $type eq "CSSValue"; + return 1 if $type eq "CSSRuleList"; + return 1 if $type eq "Document"; + return 1 if $type eq "DocumentFragment"; + return 1 if $type eq "DocumentType"; + return 1 if $type eq "Element"; + return 1 if $type eq "EntityReference"; + return 1 if $type eq "Event"; + return 1 if $type eq "HTMLCollection"; + return 1 if $type eq "HTMLDocument"; + return 1 if $type eq "HTMLElement"; + return 1 if $type eq "HTMLOptionsCollection"; + return 1 if $type eq "ImageData"; + return 1 if $type eq "MediaError"; + return 1 if $type eq "MimeType"; + return 1 if $type eq "Node"; + return 1 if $type eq "NodeList"; + return 1 if $type eq "NodeFilter"; + return 1 if $type eq "NodeIterator"; + return 1 if $type eq "NSResolver"; + return 1 if $type eq "Plugin"; + return 1 if $type eq "ProcessingInstruction"; + return 1 if $type eq "Range"; + return 1 if $type eq "Text"; + return 1 if $type eq "TextMetrics"; + return 1 if $type eq "TimeRanges"; + return 1 if $type eq "TreeWalker"; + return 1 if $type eq "WebKitCSSMatrix"; + return 1 if $type eq "WebKitPoint"; + return 1 if $type eq "XPathExpression"; + return 1 if $type eq "XPathNSResolver"; + return 1 if $type eq "XPathResult"; + + return 1 if $type eq "SVGAngle"; + return 1 if $type eq "SVGElementInstance"; + return 1 if $type eq "SVGElementInstanceList"; + return 1 if $type =~ /^SVGPathSeg/; + + return 1 if $type =~ /^SVGAnimated/; + + return 0; +} + +sub IsVideoClassName +{ + my $class = shift; + return 1 if $class eq "V8HTMLAudioElement"; + return 1 if $class eq "V8HTMLMediaElement"; + return 1 if $class eq "V8HTMLSourceElement"; + return 1 if $class eq "V8HTMLVideoElement"; + return 1 if $class eq "V8MediaError"; + return 1 if $class eq "V8TimeRanges"; + + return 0; +} + +sub IsWorkerClassName +{ + my $class = shift; + return 1 if $class eq "V8Worker"; + return 1 if $class eq "V8WorkerContext"; + return 1 if $class eq "V8WorkerLocation"; + return 1 if $class eq "V8WorkerNavigator"; + + return 0; +} + +sub GetNativeType +{ + my $type = shift; + my $isParameter = shift; + + if ($type eq "float" or $type eq "AtomicString" or $type eq "double") { + return $type + } + + return "int" if $type eq "short" or $type eq "unsigned short"; + return "int" if $type eq "long" or $type eq "unsigned long"; + return "unsigned long long" if $type eq "unsigned long long"; + return "bool" if $type eq "boolean"; + return "String" if $type eq "DOMString"; + return "Range::CompareHow" if $type eq "CompareHow"; + return "FloatRect" if $type eq "SVGRect"; + return "FloatPoint" if $type eq "SVGPoint"; + return "TransformationMatrix" if $type eq "SVGMatrix"; + return "SVGTransform" if $type eq "SVGTransform"; + return "SVGLength" if $type eq "SVGLength"; + return "double" if $type eq "SVGNumber"; + return "SVGPaint::SVGPaintType" if $type eq "SVGPaintType"; + return "DOMTimeStamp" if $type eq "DOMTimeStamp"; + return "unsigned" if $type eq "RGBColor"; + return "Node*" if $type eq "EventTarget" and $isParameter; + + return "String" if $type eq "DOMUserData"; # temporary hack, TODO + + # temporary hack + return "RefPtr<NodeFilter>" if $type eq "NodeFilter"; + + return "RefPtr<${type}>" if IsRefPtrType($type) and not $isParameter; + + # Default, assume native type is a pointer with same type name as idl type + return "${type}*"; +} + + +my %typeCanFailConversion = ( + "AtomicString" => 0, + "Attr" => 1, + "CompareHow" => 0, + "DOMString" => 0, + "DOMWindow" => 0, + "DocumentType" => 0, + "Element" => 0, + "Event" => 0, + "EventListener" => 0, + "EventTarget" => 0, + "HTMLElement" => 0, + "HTMLOptionElement" => 0, + "Node" => 0, + "NodeFilter" => 0, + "MessagePort" => 0, + "NSResolver" => 0, + "Range" => 0, + "SQLResultSet" => 0, + "SVGAngle" => 0, + "SVGElement" => 0, + "SVGLength" => 0, + "SVGMatrix" => 0, + "SVGNumber" => 0, + "SVGPaintType" => 0, + "SVGPathSeg" => 0, + "SVGPoint" => 0, + "SVGRect" => 0, + "SVGTransform" => 0, + "VoidCallback" => 1, + "WebKitCSSMatrix" => 0, + "WebKitPoint" => 0, + "XPathEvaluator" => 0, + "XPathNSResolver" => 0, + "XPathResult" => 0, + "boolean" => 0, + "double" => 0, + "float" => 0, + "long" => 0, + "unsigned long" => 0, + "unsigned short" => 0, +); + + +sub TranslateParameter +{ + my $signature = shift; + + # The IDL uses some pseudo-types which don't really exist. + if ($signature->type eq "TimeoutHandler") { + $signature->type("DOMString"); + } +} + +sub BasicTypeCanFailConversion +{ + # As can been seen from the above, no basic types can fail conversion. + return 0; +} + +sub TypeCanFailConversion +{ + my $signature = shift; + + my $type = $codeGenerator->StripModule($signature->type); + + $implIncludes{"ExceptionCode.h"} = 1 if $type eq "Attr"; + + return $typeCanFailConversion{$type} if exists $typeCanFailConversion{$type}; + + die "Don't know whether a JS value can fail conversion to type $type."; +} + +sub JSValueToNative +{ + my $signature = shift; + my $value = shift; + my $okParam = shift; + my $maybeOkParam = $okParam ? ", ${okParam}" : ""; + + my $type = $codeGenerator->StripModule($signature->type); + + return "$value" if $type eq "JSObject"; + return "$value->BooleanValue()" if $type eq "boolean"; + return "static_cast<$type>($value->NumberValue())" if $type eq "float" or $type eq "double"; + return "$value->NumberValue()" if $type eq "SVGNumber"; + + return "ToInt32($value${maybeOkParam})" if $type eq "unsigned long" or $type eq "unsigned short" or $type eq "long"; + return "static_cast<Range::CompareHow>($value->Int32Value())" if $type eq "CompareHow"; + return "static_cast<SVGPaint::SVGPaintType>($value->ToInt32()->Int32Value())" if $type eq "SVGPaintType"; + + return "ToWebCoreString($value)" if $type eq "AtomicString" or $type eq "DOMUserData"; + if ($type eq "DOMString") { + return "valueToStringWithNullCheck($value)" if $signature->extendedAttributes->{"ConvertNullToNullString"}; + return "valueToStringWithNullOrUndefinedCheck($value)" if $signature->extendedAttributes->{"ConvertUndefinedOrNullToNullString"}; + return "ToWebCoreString($value)"; + } + + if ($type eq "NodeFilter") { + return "V8Proxy::ToNativeNodeFilter($value)"; + } + + if ($type eq "SVGRect") { + $implIncludes{"FloatRect.h"} = 1; + } + + if ($type eq "SVGPoint") { + $implIncludes{"FloatPoint.h"} = 1; + } + + # Default, assume autogenerated type conversion routines + $implIncludes{"v8_proxy.h"} = 1; + if ($type eq "EventTarget") { + $implIncludes{"V8Node.h"} = 1; + + # EventTarget is not in DOM hierarchy, but all Nodes are EventTarget. + return "V8Node::HasInstance($value) ? V8Proxy::DOMWrapperToNode<Node>($value) : 0"; + } + + AddIncludesForType($type); + # $implIncludes{"$type.h"} = 1 unless AvoidInclusionOfType($type); + + if (IsDOMNodeType($type)) { + $implIncludes{"V8${type}.h"} = 1; + + # Perform type checks on the parameter, if it is expected Node type, + # return NULL. + return "V8${type}::HasInstance($value) ? V8Proxy::DOMWrapperToNode<${type}>($value) : 0"; + + } else { + # TODO: Temporary to avoid Window name conflict. + my $classIndex = uc($type); + my $implClassName = ${type}; + + $implIncludes{"V8$type.h"} = 1; + + if ($codeGenerator->IsPodType($type)) { + my $nativeType = GetNativeType($type); + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + + # TODO(jhass): perform type checking like others??? + return "*V8Proxy::ToNativeObject<V8SVGPODTypeWrapper<${nativeType}> >(V8ClassIndex::${classIndex}, $value)" + } + + $implIncludes{"V8${type}.h"} = 1; + + # Perform type checks on the parameter, if it is expected Node type, + # return NULL. + return "V8${type}::HasInstance($value) ? V8Proxy::ToNativeObject<${implClassName}>(V8ClassIndex::${classIndex}, $value) : 0"; + } +} + + +sub GetV8HeaderName +{ + my $type = shift; + return "V8" . GetImplementationFileName($type); +} + + +sub CreateCustomSignature +{ + my $function = shift; + my $count = @{$function->parameters}; + my $name = $function->signature->name; + my $result = " const int ${name}_argc = ${count};\n" . + " v8::Handle<v8::FunctionTemplate> ${name}_argv[${name}_argc] = { "; + my $first = 1; + foreach my $parameter (@{$function->parameters}) { + if ($first) { $first = 0; } + else { $result .= ", "; } + if (IsWrapperType($parameter->type)) { + my $type = $parameter->type; + my $header = GetV8HeaderName($type); + $implIncludes{$header} = 1; + $result .= "V8${type}::GetRawTemplate()"; + } else { + $result .= "v8::Handle<v8::FunctionTemplate>()"; + } + } + $result .= " };\n"; + $result .= " v8::Handle<v8::Signature> ${name}_signature = v8::Signature::New(desc, ${name}_argc, ${name}_argv);\n"; + return $result; +} + + +sub RequiresCustomSignature +{ + my $function = shift; + # No signature needed for Custom function + if ($function->signature->extendedAttributes->{"Custom"} || + $function->signature->extendedAttributes->{"V8Custom"}) { + return 0; + } + + foreach my $parameter (@{$function->parameters}) { + if (IsWrapperType($parameter->type)) { + return 1; + } + } + return 0; +} + + +my %non_wrapper_types = ( + 'float' => 1, + 'AtomicString' => 1, + 'double' => 1, + 'short' => 1, + 'unsigned short' => 1, + 'long' => 1, + 'unsigned long' => 1, + 'boolean' => 1, + 'DOMString' => 1, + 'CompareHow' => 1, + 'SVGRect' => 1, + 'SVGPoint' => 1, + 'SVGMatrix' => 1, + 'SVGTransform' => 1, + 'SVGLength' => 1, + 'SVGNumber' => 1, + 'SVGPaintType' => 1, + 'DOMTimeStamp' => 1, + 'JSObject' => 1, + 'EventTarget' => 1, + 'NodeFilter' => 1, + 'EventListener' => 1 +); + + +sub IsWrapperType +{ + my $type = $codeGenerator->StripModule(shift); + return !($non_wrapper_types{$type}); +} + +sub IsDOMNodeType +{ + my $type = shift; + + return 1 if $type eq 'Attr'; + return 1 if $type eq 'CDATASection'; + return 1 if $type eq 'Comment'; + return 1 if $type eq 'Document'; + return 1 if $type eq 'DocumentFragment'; + return 1 if $type eq 'DocumentType'; + return 1 if $type eq 'Element'; + return 1 if $type eq 'EntityReference'; + return 1 if $type eq 'HTMLCanvasElement'; + return 1 if $type eq 'HTMLDocument'; + return 1 if $type eq 'HTMLElement'; + return 1 if $type eq 'HTMLFormElement'; + return 1 if $type eq 'HTMLTableCaptionElement'; + return 1 if $type eq 'HTMLTableSectionElement'; + return 1 if $type eq 'Node'; + return 1 if $type eq 'ProcessingInstruction'; + return 1 if $type eq 'SVGElement'; + return 1 if $type eq 'SVGDocument'; + return 1 if $type eq 'SVGSVGElement'; + return 1 if $type eq 'SVGUseElement'; + return 1 if $type eq 'Text'; + + return 0; +} + + +sub NativeToJSValue +{ + my $signature = shift; + my $value = shift; + my $type = $codeGenerator->StripModule($signature->type); + my $className= "V8$type"; + + return "v8::Date::New(static_cast<double>($value))" if $type eq "DOMTimeStamp"; + return "$value ? v8::True() : v8::False()" if $type eq "boolean"; + return "v8::Undefined()" if $type eq "void"; + + # For all the types where we use 'int' as the representation type, + # we use Integer::New which has a fast Smi conversion check. + return "v8::Integer::New($value)" if GetNativeType($type) eq "int"; + + return "v8::Number::New($value)" if $codeGenerator->IsPrimitiveType($type) or $type eq "SVGPaintType"; + + if ($codeGenerator->IsStringType($type)) { + my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"}; + if (defined $conv) { + return "v8StringOrNull($value)" if $conv eq "Null"; + return "v8StringOrUndefined($value)" if $conv eq "Undefined"; + return "v8StringOrFalse($value)" if $conv eq "False"; + + die "Unknown value for ConvertNullStringTo extended attribute"; + } + return "v8String($value)"; + } + + # V8 specific. + my $implClassName = $type; + AddIncludesForType($type); + # $implIncludes{GetImplementationFileName($type)} = 1 unless AvoidInclusionOfType($type); + + # special case for non-DOM node interfaces + if (IsDOMNodeType($type)) { + return "V8Proxy::NodeToV8Object($value)"; + } + + if ($type eq "EventTarget" or $type eq "SVGElementInstance") { + return "V8Proxy::EventTargetToV8Object($value)"; + } + + if ($type eq "Event") { + return "V8Proxy::EventToV8Object($value)"; + } + + if ($type eq "EventListener") { + return "V8Proxy::EventListenerToV8Object($value)"; + } + + if ($type eq "RGBColor") { + return "V8Proxy::ToV8Object(V8ClassIndex::RGBCOLOR, new RGBColor($value))"; + } + + if ($type eq "WorkerLocation" or $type eq "WorkerNavigator") { + $implIncludes{"WorkerContextExecutionProxy.h"} = 1; + my $classIndex = uc($type); + + return "WorkerContextExecutionProxy::ToV8Object(V8ClassIndex::$classIndex, $value)"; + } + + else { + $implIncludes{"wtf/RefCounted.h"} = 1; + $implIncludes{"wtf/RefPtr.h"} = 1; + my $classIndex = uc($type); + + if ($codeGenerator->IsPodType($type)) { + $value = GenerateSVGStaticPodTypeWrapper($type, $value); + } + + return "V8Proxy::ToV8Object(V8ClassIndex::$classIndex, $value)"; + } +} + +sub GenerateSVGStaticPodTypeWrapper { + my $type = shift; + my $value = shift; + + $implIncludes{"V8$type.h"}=1; + $implIncludes{"V8SVGPODTypeWrapper.h"} = 1; + + my $nativeType = GetNativeType($type); + return "new V8SVGStaticPODTypeWrapper<$nativeType>($value)"; +} + +# Internal helper +sub WriteData +{ + if (defined($IMPL)) { + # Write content to file. + print $IMPL @implContentHeader; + + print $IMPL @implFixedHeader; + + foreach my $implInclude (sort keys(%implIncludes)) { + my $checkType = $implInclude; + $checkType =~ s/\.h//; + + print $IMPL "#include \"$implInclude\"\n" unless $codeGenerator->IsSVGAnimatedType($checkType); + } + + print $IMPL "\n"; + print $IMPL @implContentDecls; + print $IMPL @implContent; + close($IMPL); + undef($IMPL); + + %implIncludes = (); + @implFixedHeader = (); + @implHeaderContent = (); + @implContentDecls = (); + @implContent = (); + } + + if (defined($HEADER)) { + # Write content to file. + print $HEADER @headerContent; + close($HEADER); + undef($HEADER); + + @headerContent = (); + } +} + +sub IsSVGTypeNeedingContextParameter +{ + my $implClassName = shift; + + if ($implClassName =~ /SVG/ and not $implClassName =~ /Element/) { + return 1 unless $implClassName =~ /SVGPaint/ or $implClassName =~ /SVGColor/ or $implClassName =~ /SVGDocument/; + } + + return 0; +} + +sub GenerateSVGContextAssignment +{ + my $srcType = shift; + my $value = shift; + my $indent = shift; + + $result = GenerateSVGContextRetrieval($srcType, $indent); + $result .= $indent . "V8Proxy::SetSVGContext($value, context);\n"; + + return $result; +} + +sub GenerateSVGContextRetrieval +{ + my $srcType = shift; + my $indent = shift; + + my $srcIsPodType = $codeGenerator->IsPodType($srcType); + + my $srcObject = "imp"; + if ($srcIsPodType) { + $srcObject = "imp_wrapper"; + } + + my $contextDecl; + + if (IsSVGTypeNeedingContextParameter($srcType)) { + $contextDecl = "V8Proxy::GetSVGContext($srcObject)"; + } else { + $contextDecl = $srcObject; + } + + return $indent . "SVGElement* context = $contextDecl;\n"; +} + +sub IsSVGListMutator +{ + my $functionName = shift; + + return 1 if $functionName eq "clear"; + return 1 if $functionName eq "initialize"; + return 1 if $functionName eq "insertItemBefore"; + return 1 if $functionName eq "replaceItem"; + return 1 if $functionName eq "removeItem"; + return 1 if $functionName eq "appendItem"; + + return 0; +} + +sub IsSVGListMethod +{ + my $functionName = shift; + + return 1 if $functionName eq "getFirst"; + return 1 if $functionName eq "getLast"; + return 1 if $functionName eq "getItem"; + + return IsSVGListMutator($functionName); +} + +sub IsSVGListTypeNeedingSpecialHandling +{ + my $className = shift; + + return 1 if $className eq "SVGPointList"; + return 1 if $className eq "SVGTransformList"; + + return 0; +} + +sub DebugPrint +{ + my $output = shift; + + print $output; + print "\n"; +} diff --git a/V8Binding/scripts/IDLParser.pm b/V8Binding/scripts/IDLParser.pm new file mode 100644 index 0000000..eb0eab5 --- /dev/null +++ b/V8Binding/scripts/IDLParser.pm @@ -0,0 +1,441 @@ +# +# KDOM IDL parser +# +# Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org> +# +# This file is part of the KDE project +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +package IDLParser; + +use IDLStructure; + +use constant MODE_UNDEF => 0; # Default mode. + +use constant MODE_MODULE => 10; # 'module' section +use constant MODE_INTERFACE => 11; # 'interface' section +use constant MODE_EXCEPTION => 12; # 'exception' section +use constant MODE_ALIAS => 13; # 'alias' section + +# Helper variables +my @temporaryContent = ""; + +my $parseMode = MODE_UNDEF; +my $preservedParseMode = MODE_UNDEF; + +my $beQuiet; # Should not display anything on STDOUT? +my $document = 0; # Will hold the resulting 'idlDocument' + +my $directive = ""; + +# Default Constructor +sub new +{ + my $object = shift; + my $reference = { }; + + $document = 0; + $beQuiet = shift; + + bless($reference, $object); + return $reference; +} + + +sub ParseInheritance +{ + my $object = shift; + my $fileName = shift; + my $defines = shift; + my $preprocessor = shift; + + $directive = "inheritance"; + return $object->ParseImpl($fileName, $defines, $preprocessor); +} + +# Returns the parsed 'idlDocument' +sub Parse +{ + my $object = shift; + my $fileName = shift; + my $defines = shift; + my $preprocessor = shift; + + $directive = ""; + return $object->ParseImpl($fileName, $defines, $preprocessor); +} + +sub ParseImpl +{ + my $object = shift; + my $fileName = shift; + my $defines = shift; + my $preprocessor = shift; + + if (!$preprocessor) { + $preprocessor = "/usr/bin/gcc -E -P -x c++"; + } + + if (!$defines) { + $defines = ""; + } + + print " | *** Starting to parse $fileName...\n |\n" unless $beQuiet; + + open FILE, $preprocessor . " " . join(" ", (map { "-D$_" } split(/ /, $defines))) . " ". $fileName . "|" or die "Could not open $fileName"; + my @documentContent = <FILE>; + close FILE; + + my $dataAvailable = 0; + + # Simple IDL Parser (tm) + foreach (@documentContent) { + my $newParseMode = $object->DetermineParseMode($_); + + if ($newParseMode ne MODE_UNDEF) { + if ($dataAvailable eq 0) { + $dataAvailable = 1; # Start node building... + } else { + $object->ProcessSection(); + } + } + + # Update detected data stream mode... + if ($newParseMode ne MODE_UNDEF) { + $parseMode = $newParseMode; + } + + push(@temporaryContent, $_); + } + + # Check if there is anything remaining to parse... + if (($parseMode ne MODE_UNDEF) and ($#temporaryContent > 0)) { + $object->ProcessSection(); + } + + print " | *** Finished parsing!\n" unless $beQuiet; + + $document->fileName($fileName); + + return $document; +} + +sub ParseModule +{ + my $object = shift; + my $dataNode = shift; + + print " |- Trying to parse module...\n" unless $beQuiet; + + my $data = join("", @temporaryContent); + $data =~ /$IDLStructure::moduleSelector/; + + my $moduleName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)")); + $dataNode->module($moduleName); + + print " |----> Module; NAME \"$moduleName\"\n |-\n |\n" unless $beQuiet; +} + +sub dumpExtendedAttributes +{ + my $padStr = shift; + my $attrs = shift; + + if (!%{$attrs}) { + return ""; + } + + my @temp; + while (($name, $value) = each(%{$attrs})) { + push(@temp, "$name=$value"); + } + + return $padStr . "[" . join(", ", @temp) . "]"; +} + +sub parseExtendedAttributes +{ + my $str = shift; + $str =~ s/\[\s*(.*)\]/$1/g; + + my %attrs = (); + + foreach my $value (split(/\s*,\s*/, $str)) { + ($name,$value) = split(/\s*=\s*/, $value, 2); + + # Attributes with no value are set to be true + $value = 1 unless defined $value; + $attrs{$name} = $value; + } + + return \%attrs; +} + +sub ParseInterface +{ + my $object = shift; + my $dataNode = shift; + my $sectionName = shift; + + my $data = join("", @temporaryContent); + + # Look for end-of-interface mark + $data =~ /};/g; + $data = substr($data, index($data, $sectionName), pos($data) - length($data)); + + $data =~ s/[\n\r]/ /g; + + # Beginning of the regexp parsing magic + if ($sectionName eq "exception") { + print " |- Trying to parse exception...\n" unless $beQuiet; + + my $exceptionName = ""; + my $exceptionData = ""; + my $exceptionDataName = ""; + my $exceptionDataType = ""; + + # Match identifier of the exception, and enclosed data... + $data =~ /$IDLStructure::exceptionSelector/; + $exceptionName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)")); + $exceptionData = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)")); + + ('' =~ /^/); # Reset variables needed for regexp matching + + # ... parse enclosed data (get. name & type) + $exceptionData =~ /$IDLStructure::exceptionSubSelector/; + $exceptionDataType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$data\n)")); + $exceptionDataName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)")); + + # Fill in domClass datastructure + $dataNode->name($exceptionName); + + my $newDataNode = new domAttribute(); + $newDataNode->type("readonly attribute"); + $newDataNode->signature(new domSignature()); + + $newDataNode->signature->name($exceptionDataName); + $newDataNode->signature->type($exceptionDataType); + + my $arrayRef = $dataNode->attributes; + push(@$arrayRef, $newDataNode); + + print " |----> Exception; NAME \"$exceptionName\" DATA TYPE \"$exceptionDataType\" DATA NAME \"$exceptionDataName\"\n |-\n |\n" unless $beQuiet; + } elsif ($sectionName eq "interface") { + print " |- Trying to parse interface...\n" unless $beQuiet; + + my $interfaceName = ""; + my $interfaceData = ""; + + # Match identifier of the interface, and enclosed data... + $data =~ /$IDLStructure::interfaceSelector/; + + $interfaceExtendedAttributes = (defined($1) ? $1 : " "); chop($interfaceExtendedAttributes); + $interfaceName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$data\n)")); + $interfaceBase = (defined($3) ? $3 : ""); + $interfaceData = (defined($4) ? $4 : die("Parsing error!\nSource:\n$data\n)")); + + # Fill in known parts of the domClass datastructure now... + $dataNode->name($interfaceName); + $dataNode->extendedAttributes(parseExtendedAttributes($interfaceExtendedAttributes)); + + # Inheritance detection + my @interfaceParents = split(/,/, $interfaceBase); + foreach(@interfaceParents) { + my $line = $_; + $line =~ s/\s*//g; + + my $arrayRef = $dataNode->parents; + push(@$arrayRef, $line); + } + + return if ($directive eq "inheritance"); + + $interfaceData =~ s/[\n\r]/ /g; + my @interfaceMethods = split(/;/, $interfaceData); + + foreach my $line (@interfaceMethods) { + if ($line =~ /[ \t]attribute[ \t]/) { + $line =~ /$IDLStructure::interfaceAttributeSelector/; + + my $attributeType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)")); + my $attributeExtendedAttributes = (defined($2) ? $2 : " "); chop($attributeExtendedAttributes); + + my $attributeDataType = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + my $attributeDataName = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)")); + + ('' =~ /^/); # Reset variables needed for regexp matching + + $line =~ /$IDLStructure::getterRaisesSelector/; + my $getterException = (defined($1) ? $1 : ""); + + $line =~ /$IDLStructure::setterRaisesSelector/; + my $setterException = (defined($1) ? $1 : ""); + + my $newDataNode = new domAttribute(); + $newDataNode->type($attributeType); + $newDataNode->signature(new domSignature()); + + $newDataNode->signature->name($attributeDataName); + $newDataNode->signature->type($attributeDataType); + $newDataNode->signature->extendedAttributes(parseExtendedAttributes($attributeExtendedAttributes)); + + my $arrayRef = $dataNode->attributes; + push(@$arrayRef, $newDataNode); + + print " | |> Attribute; TYPE \"$attributeType\" DATA NAME \"$attributeDataName\" DATA TYPE \"$attributeDataType\" GET EXCEPTION? \"$getterException\" SET EXCEPTION? \"$setterException\"" . + dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet; + + $getterException =~ s/\s+//g; + $setterException =~ s/\s+//g; + @{$newDataNode->getterExceptions} = split(/,/, $getterException); + @{$newDataNode->setterExceptions} = split(/,/, $setterException); + } elsif (($line !~ s/^\s*$//g) and ($line !~ /^\s*const/)) { + $line =~ /$IDLStructure::interfaceMethodSelector/ or die "Parsing error!\nSource:\n$line\n)"; + + my $methodExtendedAttributes = (defined($1) ? $1 : " "); chop($methodExtendedAttributes); + my $methodType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + my $methodName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + my $methodSignature = (defined($4) ? $4 : die("Parsing error!\nSource:\n$line\n)")); + + ('' =~ /^/); # Reset variables needed for regexp matching + + $line =~ /$IDLStructure::raisesSelector/; + my $methodException = (defined($1) ? $1 : ""); + + my $newDataNode = new domFunction(); + + $newDataNode->signature(new domSignature()); + $newDataNode->signature->name($methodName); + $newDataNode->signature->type($methodType); + $newDataNode->signature->extendedAttributes(parseExtendedAttributes($methodExtendedAttributes)); + + print " | |- Method; TYPE \"$methodType\" NAME \"$methodName\" EXCEPTION? \"$methodException\"" . + dumpExtendedAttributes("\n | ", $newDataNode->signature->extendedAttributes) . "\n" unless $beQuiet; + + $methodException =~ s/\s+//g; + @{$newDataNode->raisesExceptions} = split(/,/, $methodException); + + my @params = split(/,/, $methodSignature); + foreach(@params) { + my $line = $_; + + $line =~ /$IDLStructure::interfaceParameterSelector/; + my $paramExtendedAttributes = (defined($1) ? $1 : " "); chop($paramExtendedAttributes); + my $paramType = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + my $paramName = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + + my $paramDataNode = new domSignature(); + $paramDataNode->name($paramName); + $paramDataNode->type($paramType); + $paramDataNode->extendedAttributes(parseExtendedAttributes($paramExtendedAttributes)); + + my $arrayRef = $newDataNode->parameters; + push(@$arrayRef, $paramDataNode); + + print " | |> Param; TYPE \"$paramType\" NAME \"$paramName\"" . + dumpExtendedAttributes("\n | ", $paramDataNode->extendedAttributes) . "\n" unless $beQuiet; + } + + my $arrayRef = $dataNode->functions; + push(@$arrayRef, $newDataNode); + } elsif ($line =~ /^\s*const/) { + $line =~ /$IDLStructure::constantSelector/; + my $constType = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)")); + my $constName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + my $constValue = (defined($3) ? $3 : die("Parsing error!\nSource:\n$line\n)")); + + my $newDataNode = new domConstant(); + $newDataNode->name($constName); + $newDataNode->type($constType); + $newDataNode->value($constValue); + + my $arrayRef = $dataNode->constants; + push(@$arrayRef, $newDataNode); + + print " | |> Constant; TYPE \"$constType\" NAME \"$constName\" VALUE \"$constValue\"\n" unless $beQuiet; + } + } + + print " |----> Interface; NAME \"$interfaceName\"" . + dumpExtendedAttributes("\n | ", $dataNode->extendedAttributes) . "\n |-\n |\n" unless $beQuiet; + } +} + +# Internal helper +sub DetermineParseMode +{ + my $object = shift; + my $line = shift; + + my $mode = MODE_UNDEF; + if ($_ =~ /module/) { + $mode = MODE_MODULE; + } elsif ($_ =~ /interface/) { + $mode = MODE_INTERFACE; + } elsif ($_ =~ /exception/) { + $mode = MODE_EXCEPTION; + } elsif ($_ =~ /alias/) { + $mode = MODE_ALIAS; + } + + return $mode; +} + +# Internal helper +sub ProcessSection +{ + my $object = shift; + + if ($parseMode eq MODE_MODULE) { + die ("Two modules in one file! Fatal error!\n") if ($document ne 0); + $document = new idlDocument(); + $object->ParseModule($document); + } elsif ($parseMode eq MODE_INTERFACE) { + my $node = new domClass(); + $object->ParseInterface($node, "interface"); + + die ("No module specified! Fatal Error!\n") if ($document eq 0); + my $arrayRef = $document->classes; + push(@$arrayRef, $node); + } elsif($parseMode eq MODE_EXCEPTION) { + my $node = new domClass(); + $object->ParseInterface($node, "exception"); + + die ("No module specified! Fatal Error!\n") if ($document eq 0); + my $arrayRef = $document->classes; + push(@$arrayRef, $node); + } elsif($parseMode eq MODE_ALIAS) { + print " |- Trying to parse alias...\n" unless $beQuiet; + + my $line = join("", @temporaryContent); + $line =~ /$IDLStructure::aliasSelector/; + + my $interfaceName = (defined($1) ? $1 : die("Parsing error!\nSource:\n$line\n)")); + my $wrapperName = (defined($2) ? $2 : die("Parsing error!\nSource:\n$line\n)")); + + print " |----> Alias; INTERFACE \"$interfaceName\" WRAPPER \"$wrapperName\"\n |-\n |\n" unless $beQuiet; + + # FIXME: Check if alias is already in aliases + my $aliases = $document->aliases; + $aliases->{$interfaceName} = $wrapperName; + } + + @temporaryContent = ""; +} + +1; diff --git a/V8Binding/scripts/generate-bindings.pl b/V8Binding/scripts/generate-bindings.pl new file mode 100644 index 0000000..da5d09a --- /dev/null +++ b/V8Binding/scripts/generate-bindings.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2005 Apple Computer, Inc. +# Copyright (C) 2006 Anders Carlsson <andersca@mac.com> +# +# This file is part of WebKit +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# aint with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# + +# This script is a temporary hack. +# Files are generated in the source directory, when they really should go +# to the DerivedSources directory. +# This should also eventually be a build rule driven off of .idl files +# however a build rule only solution is blocked by several radars: +# <rdar://problems/4251781&4251785> + +use strict; + +use File::Path; +use Getopt::Long; +use Cwd; + +use IDLParser; +use CodeGenerator; + +my @idlDirectories; +my $outputDirectory; +my $generator; +my $defines; +my $preprocessor; + +GetOptions('include=s@' => \@idlDirectories, + 'outputdir=s' => \$outputDirectory, + 'generator=s' => \$generator, + 'defines=s' => \$defines, + 'preprocessor=s' => \$preprocessor); + +my $idlFile = $ARGV[0]; + +die('Must specify input file.') unless defined($idlFile); +die('Must specify IDL search path.') unless @idlDirectories; +die('Must specify generator') unless defined($generator); +die('Must specify input file.') unless defined($idlFile); +die('Must specify output directory.') unless defined($outputDirectory); +die('Must specify defines') unless defined($defines); + +$defines =~ s/^\s+|\s+$//g; # trim whitespace + +# Parse the given IDL file. +my $parser = IDLParser->new(1); +my $document = $parser->Parse($idlFile, $defines, $preprocessor); + +# Generate desired output for given IDL file. +my $codeGen = CodeGenerator->new(\@idlDirectories, $generator, $outputDirectory, 0, $preprocessor); +$codeGen->ProcessDocument($document, $defines); |