# Copyright (C) 2005, 2006 Nikolas Zimmermann # Copyright (C) 2006 Anders Carlsson # Copyright (C) 2006 Samuel Weinig # Copyright (C) 2006 Alexey Proskuryakov # Copyright (C) 2006 Apple Computer, Inc. # Copyright (C) 2007, 2008, 2009, 2012 Google Inc. # Copyright (C) 2009 Cameron McCormack # Copyright (C) Research In Motion Limited 2010. All rights reserved. # Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) # Copyright (C) 2012 Ericsson AB. All rights reserved. # Copyright (C) 2013 Stefan Radomski # # 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. # package CodeGeneratorArabicaV8; use strict; use Data::Dumper; use Carp qw/longmess cluck confess/; use constant FileNamePrefix => "V8"; my $codeGenerator; my @headerContent = (); my @implContentHeader = (); my @implContent = (); my @implContentDecls = (); my %implIncludes = (); my %headerIncludes = (); # Default .h template my $headerTemplate = << 'EOF'; /** * @file * @author This file has been generated by generate-bindings.pl. DO NOT MODIFY! * @copyright Simplified BSD * * @cond * This program is free software: you can redistribute it and/or modify * it under the terms of the FreeBSD license as published by the FreeBSD * project. * * This program 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. * * You should have received a copy of the FreeBSD license along with this * program. If not, see . * @endcond */ EOF # Default constructor sub new { my $object = shift; my $reference = { }; $codeGenerator = shift; bless($reference, $object); return $reference; } sub GenerateInterface { my $object = shift; my $interface = shift; # print Dumper($interface); # Start actual generation if ($interface->extendedAttributes->{"Callback"}) { die(); $object->GenerateCallbackHeader($interface); $object->GenerateCallbackImplementation($interface); } else { $object->GenerateHeader($interface); $object->GenerateImplementation($interface); } } sub AddToImplIncludes { my $header = shift; my $conditional = shift; if ($header eq "V8bool.h") { confess(); } if (not $conditional) { $implIncludes{$header} = 1; } elsif (not exists($implIncludes{$header})) { $implIncludes{$header} = $conditional; } else { my $oldValue = $implIncludes{$header}; if ($oldValue ne 1) { my %newValue = (); $newValue{$conditional} = 1; foreach my $condition (split(/\|/, $oldValue)) { $newValue{$condition} = 1; } $implIncludes{$header} = join("|", sort keys %newValue); } } } sub GenerateHeader { my $object = shift; my $interface = shift; my $interfaceName = $interface->name; my $extensions = $interface->extendedAttributes; # print Dumper($extensions); # Copy contents of parent interfaces except the first parent. my @parents; $codeGenerator->AddMethodsConstantsAndAttributesFromParentInterfaces($interface, \@parents, 1); $codeGenerator->LinkOverloadedFunctions($interface); # - Add default header template push(@headerContent, GenerateHeaderContentHeader($interface)); $headerIncludes{"string"} = 1; $headerIncludes{"uscxml/plugins/datamodel/ecmascript/v8/V8DOM.h"} = 1; $headerIncludes{"DOM/Node.hpp"} = 1; $headerIncludes{"v8.h"} = 1; if ($interfaceName =~ /.*Array$/ or $interfaceName =~ /^ArrayBuffer.*/) { $headerIncludes{"../../TypedArray.h"} = 1; } foreach (@{$interface->parents}) { my $parent = $_; $headerIncludes{"V8${parent}.h"} = 1; } push(@headerContent, "#include \\n"); foreach my $headerInclude (sort keys(%headerIncludes)) { if ($headerInclude =~ /wtf|v8\.h/) { push(@headerContent, "#include \<${headerInclude}\>\n"); } else { push(@headerContent, "#include \"${headerInclude}\"\n"); } } push(@headerContent, ""); push(@headerContent, "\nnamespace Arabica {"); push(@headerContent, "\nnamespace DOM {\n"); push(@headerContent, "\nclass V8${interfaceName} {"); push(@headerContent, "\npublic:"); my $wrapperType = IdlToWrapperType($interfaceName); push(@headerContent, <{'DontDestroyWrapped'}) { push(@headerContent, "\n V8_DESTRUCTOR_KEEP_WRAPPED(V8${interfaceName}Private);"); } else { push(@headerContent, "\n V8_DESTRUCTOR(V8${interfaceName}Private);"); } push(@headerContent, "\n static bool hasInstance(v8::Handle);"); push(@headerContent, "\n"); # callbacks for actual functions my %generated; foreach my $function (@{$interface->functions}) { my $name = $function->signature->name; my $attrExt = $function->signature->extendedAttributes; my $custom = ($attrExt->{'Custom'} ? "Custom" : ""); next if (exists $generated{"${name}${custom}Callback"}); push(@headerContent, "\n static v8::Handle ${name}${custom}Callback(const v8::Arguments&);"); $generated{"${name}${custom}Callback"} = 1; } push(@headerContent, "\n"); # attribute getter and setters foreach my $attribute (@{$interface->attributes}) { my $name = $attribute->signature->name; my $attrExt = $attribute->signature->extendedAttributes; my $customGetter = ($attrExt->{'CustomGetter'} ? "Custom" : ""); my $customSetter = ($attrExt->{'CustomSetter'} ? "Custom" : ""); push(@headerContent, "\n static v8::Handle ${name}${customGetter}AttrGetter(v8::Local property, const v8::AccessorInfo& info);"); if (!IsReadonly($attribute)) { push(@headerContent, "\n static void ${name}${customSetter}AttrSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info);"); } } if ($extensions->{'CustomIndexedGetter'}) { push(@headerContent, "\n static v8::Handle indexedPropertyCustomGetter(uint32_t, const v8::AccessorInfo&);"); } if ($extensions->{'CustomIndexedSetter'}) { push(@headerContent, "\n static v8::Handle indexedPropertyCustomSetter(uint32_t, v8::Local, const v8::AccessorInfo&);"); } push(@headerContent, "\n"); GenerateClassPrototypeHeader($interface); push(@headerContent, "\n};\n\n}\n}\n\n"); push(@headerContent, "#endif // V8${interfaceName}" . "_h\n"); } # # Write class template prototype constructor # sub GenerateClassPrototypeHeader { my $interface = shift; my $interfaceName = $interface->name; my $extensions = $interface->extendedAttributes; if ($extensions->{'Constructors'}) { push(@headerContent, "\n"); push(@headerContent, " static v8::Handle constructor(const v8::Arguments&);\n"); push(@headerContent, " static v8::Persistent Constr;\n"); push(@headerContent, < getConstructor() { if (Constr.IsEmpty()) { v8::Handle constr = v8::FunctionTemplate::New(constructor); Constr = v8::Persistent::New(constr); } return Constr; } END } push(@headerContent, "\n static v8::Persistent Tmpl;\n"); push(@headerContent, < getTmpl() { if (Tmpl.IsEmpty()) { v8::Handle tmpl = v8::FunctionTemplate::New(); tmpl->SetClassName(v8::String::New("${interfaceName}")); tmpl->ReadOnlyPrototype(); v8::Local instance = tmpl->InstanceTemplate(); v8::Local prototype = tmpl->PrototypeTemplate(); (void)prototype; // surpress unused warnings instance->SetInternalFieldCount(1); END push(@headerContent, "\n"); foreach my $attribute (@{$interface->attributes}) { my $name = $attribute->signature->name; my $attrExt = $attribute->signature->extendedAttributes; my $customGetter = ($attrExt->{'CustomGetter'} ? "Custom" : ""); my $customSetter = ($attrExt->{'CustomSetter'} ? "Custom" : ""); my $getter = "V8${interfaceName}::${name}${customGetter}AttrGetter"; my $setter = (IsReadonly($attribute) ? "0" : "V8${interfaceName}::${name}${customSetter}AttrSetter"); push(@headerContent, <SetAccessor(v8::String::NewSymbol("${name}"), ${getter}, ${setter}, v8::External::New(0), static_cast(v8::DEFAULT), static_cast(v8::None)); END } if ($extensions->{'CustomIndexedGetter'} || $extensions->{'CustomIndexedSetter'}) { my $indexedGetter = ($extensions->{'CustomIndexedGetter'} ? "V8${interfaceName}::indexedPropertyCustomGetter" : 0); my $indexedSetter = ($extensions->{'CustomIndexedSetter'} ? "V8${interfaceName}::indexedPropertyCustomSetter" : 0); push(@headerContent, "\n instance->SetIndexedPropertyHandler(${indexedGetter}, ${indexedSetter});"); } push(@headerContent, "\n"); my %generated; foreach my $function (@{$interface->functions}) { my $name = $function->signature->name; my $attrExt = $function->signature->extendedAttributes; my $custom = ($attrExt->{'Custom'} ? "Custom" : ""); next if (exists $generated{"${name}"}); $generated{"${name}"} = 1; push(@headerContent, <Set(v8::String::NewSymbol("${name}"), v8::FunctionTemplate::New(V8${interfaceName}::${name}${custom}Callback, v8::Undefined()), static_cast(v8::DontDelete)); END } push(@headerContent, "\n"); foreach my $constant (@{$interface->constants}) { my $name = $constant->name; my $value = $constant->value; my $type = IdlToV8Type($constant->type); push(@headerContent, <Set(v8::String::NewSymbol("${name}"), ${type}::New(${value}), static_cast(v8::ReadOnly | v8::DontEnum)); prototype->Set(v8::String::NewSymbol("${name}"), ${type}::New(${value}), static_cast(v8::ReadOnly | v8::DontEnum)); END } push(@headerContent, "\n"); if (@{$interface->parents}) { my $parent = @{$interface->parents}[0]; push(@headerContent, " tmpl->Inherit(V8${parent}::getTmpl());\n"); } push(@headerContent, <::New(tmpl); } return Tmpl; } END } sub GenerateImplementationAttributes { my $interface = shift; my $interfaceName = $interface->name; my $extensions = $interface->extendedAttributes; # Generate property accessors for attributes. for (my $index = 0; $index < @{$interface->attributes}; $index++) { my $attribute = @{$interface->attributes}[$index]; my $attrType = $attribute->signature->type; my $attrName = $attribute->signature->name; my $attrExt = $attribute->signature->extendedAttributes; my $wrapperRetType = IdlToWrapperType($attrType); my $wrapperType = IdlToWrapperType($interfaceName); my $wrapperGetter; if ($attrExt->{'AttributeIsPublic'} || $extensions->{'AttributesArePublic'}) { $wrapperGetter = $attrName; } else { $wrapperGetter = IdlToWrapperAttrGetter($interface, $attribute)."()"; } # getter if (!$attrExt->{'CustomGetter'}) { push(@implContent, < V8${interfaceName}::${attrName}AttrGetter(v8::Local property, const v8::AccessorInfo& info) { v8::Local self = info.Holder(); struct V8${interfaceName}Private* privData = V8DOM::toClassPtr(self->GetInternalField(0)); END if (IsWrapperType($attrType)) { AddToImplIncludes("V8".$attrType.".h"); push(@implContent, "\n ".GenerateConditionalUndefReturn($interface, $attribute, "privData->nativeObj->${wrapperGetter}")); push(@implContent, <nativeObj->${wrapperGetter}); v8::Handle arbaicaRetCtor = V8${attrType}::getTmpl()->GetFunction(); v8::Persistent arbaicaRetObj = v8::Persistent::New(arbaicaRetCtor->NewInstance()); struct V8${attrType}::V8${attrType}Private* retPrivData = new V8${attrType}::V8${attrType}Private(); retPrivData->dom = privData->dom; retPrivData->nativeObj = arbaicaRet; arbaicaRetObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); arbaicaRetObj.MakeWeak(0, V8${attrType}::jsDestructor); return arbaicaRetObj; END } else { my $v8Type = IdlToV8Type($attrType); if ($attrType eq "DOMString") { if ($attrExt->{'EmptyAsNull'}) { push(@implContent, "\n if (privData->nativeObj->${wrapperGetter}.length() == 0)"); push(@implContent, "\n return v8::Undefined();"); } push(@implContent, "\n return ${v8Type}::New(privData->nativeObj->${wrapperGetter}.c_str());"); } else { push(@implContent, "\n return ${v8Type}::New(privData->nativeObj->${wrapperGetter});"); } } push(@implContent, "\n }\n"); } if (!$attrExt->{'CustomSetter'}) { # setter if (!IsReadonly($attribute)) { my $wrapperSetter = IdlToWrapperAttrSetter($attrName); push(@implContent, "\n void V8${interfaceName}::${attrName}AttrSetter(v8::Local property, v8::Local value, const v8::AccessorInfo& info) {"); push(@implContent, "\n v8::Local self = info.Holder();"); push(@implContent, "\n struct V8${interfaceName}Private* privData = V8DOM::toClassPtr(self->GetInternalField(0));"); my ($handle, $deref) = IdlToArgHandle($attribute->signature->type, "local".ucfirst($attribute->signature->name), "value", $interfaceName); push(@implContent, "\n $handle"); push(@implContent, "\n privData->nativeObj->${wrapperSetter}(${deref});"); push(@implContent, "\n }\n"); } } } } sub GenerateConditionalUndefReturn { my $interface = shift; my $attribute = shift; my $getterExpression = shift; return "" if ($attribute->signature->type eq "NamedNodeMap"); return "" if ($attribute->signature->type eq "NodeList"); return "if (!$getterExpression) return v8::Undefined();"; } sub GenerateConstructor { my $interface = shift; my $interfaceName = $interface->name; my $wrapperType = IdlToWrapperType($interfaceName); my $extensions = $interface->extendedAttributes; if ($extensions->{'Constructors'}) { push(@implContent, "\n v8::Handle V8${interfaceName}::constructor(const v8::Arguments& args) {"); push(@implContent, <{'Constructors'}}) { push (@variants, $fullCons); for (my $i = @{$fullCons}; $i > 0; $i--) { my $variant = @{$fullCons}[$i]; if ($variant->{'domSignature::isOptional'}) { my $slice; for (my $j = 0; $j < $i; $j++) { push(@{$slice}, @{$fullCons}[$j]); } push (@variants, $slice); } } # sort to put most determinate signatures first @variants = sort { if (@{$b} != @{$a}) { # more arguments are more determinant @{$b} <=> @{$a}; } else { my @aWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$a}); my @bWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$b}); @bWrap <=> @aWrap; } } @variants; } foreach my $constructor (@variants) { push(@implContent, " else if (args.Length() == " . @{$constructor}); for (my $i = 0; $i < @{$constructor}; $i++) { my $type = $constructor->[$i]->{'domSignature::type'}; AddToImplIncludes("V8".$type.".h") if (IsWrapperType($type)); push(@implContent, " &&\n " . IdlToTypeChecker($type, "args[$i]")); } push(@implContent, ") {\n"); my $constructorArgs; my $constructorSep = ""; for (my $i = 0; $i < @{$constructor}; $i++) { my $type = $constructor->[$i]->{'domSignature::type'}; my $name = $constructor->[$i]->{'domSignature::name'}; my ($handle, $deref) = IdlToArgHandle($type, "local".ucfirst($name), "args[$i]", $interfaceName); $constructorArgs .= ${constructorSep}.${deref}; $constructorSep = ", "; push(@implContent, "\n $handle"); } push(@implContent, "\n localInstance = new ".IdlToWrapperType($interfaceName)."(${constructorArgs});"); push(@implContent, "\n\n }"); } push(@implContent, "\n"); push(@implContent, < retCtor = V8${interfaceName}::getTmpl()->GetFunction(); v8::Persistent retObj = v8::Persistent::New(retCtor->NewInstance()); struct V8${interfaceName}::V8${interfaceName}Private* retPrivData = new V8${interfaceName}::V8${interfaceName}Private(); retPrivData->nativeObj = localInstance; retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); retObj.MakeWeak(0, V8${interfaceName}::jsDestructor); return retObj; } END } } sub GenerateImplementationFunctionCallbacks { my $interface = shift; my $interfaceName = $interface->name; my $wrapperType = IdlToWrapperType($interfaceName); my $extensions = $interface->extendedAttributes; # Generate methods for functions. my %generated; foreach my $function (@{$interface->functions}) { my $name = $function->signature->name; my $attrExt = $function->signature->extendedAttributes; my $retType = $function->signature->type; my $wrapperRetType = IdlToWrapperType($retType); next if ($attrExt->{'Custom'}); next if (exists $generated{"${name}Callback"}); $generated{"${name}Callback"} = 1; # get all functions with this name my @sameFunctions = grep($_->signature->name eq $name, @{$interface->functions}); # signature push(@implContent, < V8${interfaceName}::${name}Callback(const v8::Arguments& args) { END # get this push(@implContent, "\n v8::Local self = args.Holder();"); push(@implContent, "\n struct V8${interfaceName}Private* privData = V8DOM::toClassPtr(self->GetInternalField(0));"); # establish all variants my @variants; foreach my $functionVar (@sameFunctions) { push (@variants, $functionVar->parameters); for (my $i = @{$functionVar->parameters}; $i > 0; $i--) { my $variant = @{$functionVar->parameters}[$i]; if ($variant->{'domSignature::isOptional'}) { my $slice; for (my $j = 0; $j < $i; $j++) { push(@{$slice}, @{$functionVar->parameters}[$j]); } push (@variants, $slice); } } } # arguments to local handles push(@implContent, "\n if (false) {"); # sort to put most determinate signatures first @variants = sort { if (@{$b} != @{$a}) { # more arguments are more determinant @{$b} <=> @{$a}; } else { my @aWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$a}); my @bWrap = grep(IsWrapperType($_->{'domSignature::type'}), @{$b}); @bWrap <=> @aWrap; } } @variants; foreach my $variant (@variants) { my $parameterIndex = 0; my @argList; push(@implContent, "\n } else if (args.Length() == " . @{$variant}); for (my $i = 0; $i < @{$variant}; $i++) { my $type = $variant->[$i]->{'domSignature::type'}; push(@implContent, " &&\n " . IdlToTypeChecker($type, "args[$i]")); } push(@implContent, ")\n {"); foreach my $parameter (@{$variant}) { my $value = "args[$parameterIndex]"; my $type = $parameter->type; AddToImplIncludes("V8".$type.".h") if (IsWrapperType($type)); my ($handle, $deref) = IdlToArgHandle($parameter->type, "local".ucfirst($parameter->name), "args[${parameterIndex}]", $interfaceName); push(@implContent, "\n ${handle}"); push(@argList, $deref); $parameterIndex++; } # invoke native function with argument handles my $retNativeType = IdlToNativeType($retType); my $wrapperFunctionName = IdlToWrapperFunction($interface, $function); if (IsWrapperType($retType)) { push(@implContent, "\n\n ${retNativeType}* retVal = new $wrapperRetType(privData->nativeObj->${wrapperFunctionName}(" . join(", ", @argList) . "));\n"); } elsif ($retNativeType eq "void") { push(@implContent, "\n\n privData->nativeObj->${wrapperFunctionName}(" . join(", ", @argList) . ");\n"); } else { push(@implContent, "\n\n ${retNativeType} retVal = privData->nativeObj->${wrapperFunctionName}(" . join(", ", @argList) . ");\n"); } # wrap return type if needed if (IsWrapperType($retType)) { AddToImplIncludes("V8".$retType.".h"); push(@implContent, < retCtor = V8${retType}::getTmpl()->GetFunction(); v8::Persistent retObj = v8::Persistent::New(retCtor->NewInstance()); struct V8${retType}::V8${retType}Private* retPrivData = new V8${retType}::V8${retType}Private(); retPrivData->dom = privData->dom; retPrivData->nativeObj = retVal; retObj->SetInternalField(0, V8DOM::toExternal(retPrivData)); retObj.MakeWeak(0, V8${retType}::jsDestructor); return retObj; END } else { my $toHandleString = NativeToHandle($retNativeType, "retVal"); push(@implContent, "\n return ${toHandleString};"); } } push(@implContent, <name; my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface); my $v8InterfaceName = "V8$interfaceName"; my $wrapperType = IdlToWrapperType($interfaceName); my $extensions = $interface->extendedAttributes; AddToImplIncludes("V8${interfaceName}.h"); # Find the super descriptor. my $parentClass = ""; my $parentClassTemplate = ""; foreach (@{$interface->parents}) { my $parent = $_; AddToImplIncludes("V8${parent}.h"); $parentClass = "V8" . $parent; last; } push(@implContent, "namespace Arabica {\n"); push(@implContent, "namespace DOM {\n\n"); push(@implContent, " v8::Persistent V8${interfaceName}::Tmpl;\n"); if ($extensions->{'Constructors'}) { push(@implContent, " v8::Persistent V8${interfaceName}::Constr;\n"); GenerateConstructor($interface); } GenerateImplementationAttributes($interface); GenerateImplementationFunctionCallbacks($interface); push(@implContent, < value) { return getTmpl()->HasInstance(value); } } } END # We've already added the header for this file in implContentHeader, so remove # it from implIncludes to ensure we don't #include it twice. # delete $implIncludes{"${v8InterfaceName}.h"}; } sub WriteData { my $object = shift; my $interface = shift; my $outputDir = shift; my $outputHeadersDir = shift; my $name = $interface->name; my $prefix = FileNamePrefix; my $headerFileName = "$outputHeadersDir/$prefix$name.h"; my $implFileName = "$outputDir/$prefix$name.cpp"; # print "WriteData\n"; # print Dumper($interface); # exit(); # Update a .cpp file if the contents are changed. my $contents = $headerTemplate; $contents .= join "", @implContentHeader; my @includes = (); my %implIncludeConditions = (); foreach my $include (keys %implIncludes) { my $condition = $implIncludes{$include}; my $checkType = $include; $checkType =~ s/\.h//; next if $codeGenerator->IsSVGAnimatedType($checkType); if ($include =~ /wtf/) { $include = "\<$include\>"; } else { $include = "\"$include\""; } if ($condition eq 1) { push @includes, $include; } else { push @{$implIncludeConditions{$condition}}, $include; } } foreach my $include (sort @includes) { $contents .= "#include $include\n"; } foreach my $condition (sort keys %implIncludeConditions) { $contents .= "\n#if " . $codeGenerator->GenerateConditionalStringFromAttributeValue($condition) . "\n"; foreach my $include (sort @{$implIncludeConditions{$condition}}) { $contents .= "#include $include\n"; } $contents .= "#endif\n"; } $contents .= "\n"; $contents .= join "", @implContentDecls, @implContent; $codeGenerator->UpdateFile($implFileName, $contents); %implIncludes = (); @implContentHeader = (); @implContentDecls = (); @implContent = (); # Update a .h file if the contents are changed. $contents = join "", @headerContent; $codeGenerator->UpdateFile($headerFileName, $contents); @headerContent = (); } sub IdlToV8Type { my $idlType = shift; return "v8::Integer" if ($idlType eq "unsigned short"); return "v8::Integer" if ($idlType eq "short"); return "v8::Integer" if ($idlType eq "unsigned long"); return "v8::Integer" if ($idlType eq "long"); return "v8::String" if ($idlType eq "DOMString"); return "v8::Boolean" if ($idlType eq "boolean"); return "v8::Number" if ($idlType eq "double"); die($idlType); } sub IdlToNativeType { my $idlType = shift; return IdlToWrapperType($idlType) if (IsWrapperType($idlType)); return "std::string" if ($idlType eq "DOMString"); return "bool" if ($idlType eq "boolean"); return "short" if ($idlType eq "short"); return "long" if ($idlType eq "long"); return "unsigned short" if ($idlType eq "unsigned short"); return "unsigned long" if ($idlType eq "unsigned long"); return "void" if ($idlType eq "void"); return "char" if ($idlType eq "byte"); return "unsigned char" if ($idlType eq "octet"); return "double" if ($idlType eq "double"); return "float" if ($idlType eq "float"); die(${idlType}); } sub NativeToHandle { my $nativeType = shift; my $nativeName = shift; return ("v8::Boolean::New(${nativeName})") if ($nativeType eq "bool"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "double"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "double"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "float"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "short"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "char"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "unsigned short"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "unsigned long"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "unsigned char"); return ("v8::Number::New(${nativeName})") if ($nativeType eq "long"); return ("v8::String::New(${nativeName}.c_str())") if ($nativeType eq "std::string"); return ("v8::Undefined()") if ($nativeType eq "void"); die($nativeType); } sub IdlToWrapperType { my $idlType = shift; return "Arabica::XPath::XPathValue" if ($idlType eq "XPathResult"); return "Arabica::XPath::NodeSet" if ($idlType eq "NodeSet"); return "Arabica::DOM::Node" if ($idlType eq "Node"); return "Arabica::DOM::Element" if ($idlType eq "Element"); return "uscxml::Event" if ($idlType eq "SCXMLEvent"); return "uscxml::Storage" if ($idlType eq "Storage"); return "uscxml::ArrayBuffer" if ($idlType eq "ArrayBuffer"); return "uscxml::ArrayBufferView" if ($idlType eq "ArrayBufferView"); return "uscxml::Int8Array" if ($idlType eq "Int8Array"); return "uscxml::Uint8Array" if ($idlType eq "Uint8Array"); return "uscxml::Uint8ClampedArray" if ($idlType eq "Uint8ClampedArray"); return "uscxml::Int16Array" if ($idlType eq "Int16Array"); return "uscxml::Uint16Array" if ($idlType eq "Uint16Array"); return "uscxml::Int32Array" if ($idlType eq "Int32Array"); return "uscxml::Uint32Array" if ($idlType eq "Uint32Array"); return "uscxml::Float32Array" if ($idlType eq "Float32Array"); return "uscxml::Float64Array" if ($idlType eq "Float64Array"); return "uscxml::DataView" if ($idlType eq "DataView"); return "Arabica::DOM::${idlType}"; } sub IdlToArgHandle { my $type = shift; my $localName = shift; my $paramName = shift; my $thisType = shift; return ("v8::String::AsciiValue ${localName}(${paramName});", "*${localName}") if ($type eq "DOMString"); return ("unsigned long ${localName} = ${paramName}->ToNumber()->Uint32Value();", ${localName}) if ($type eq "unsigned long"); return ("long ${localName} = ${paramName}->ToNumber()->Int32Value();", ${localName}) if ($type eq "long"); return ("double ${localName} = ${paramName}->ToNumber()->Value();", ${localName}) if ($type eq "double"); return ("float ${localName} = ${paramName}->ToNumber()->Value();", ${localName}) if ($type eq "float"); return ("unsigned short ${localName} = ${paramName}->ToNumber()->Uint32Value();", ${localName}) if ($type eq "unsigned short"); return ("bool ${localName} = ${paramName}->ToBoolean()->BooleanValue();", ${localName}) if ($type eq "boolean"); return ("char ${localName} = ${paramName}->ToNumber()->Int32Value();", ${localName}) if ($type eq "byte"); return ("short ${localName} = ${paramName}->ToNumber()->Int32Value();", ${localName}) if ($type eq "short"); return ("unsigned char ${localName} = ${paramName}->ToNumber()->Uint32Value();", ${localName}) if ($type eq "octet"); return ("void* ${localName} = v8::External::Unwrap(${paramName}->ToObject()->GetInternalField(0));", ${localName}) if ($type eq "any"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToInteger()->Value());\n}", "${localName}") if ($type eq "long[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToNumber()->Value());\n}", "${localName}") if ($type eq "float[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToNumber()->Value());\n}", "${localName}") if ($type eq "double[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToInt32()->Value());\n}", "${localName}") if ($type eq "byte[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToInt32()->Value());\n}", "${localName}") if ($type eq "short[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToUint32()->Value());\n}", "${localName}") if ($type eq "unsigned short[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToUint32()->Value());\n}", "${localName}") if ($type eq "unsigned long[]"); return ("std::vector ${localName};\nv8::Handle ${localName}Array(v8::Array::Cast(*args[0]));\nfor (int i = 0; i < ${localName}Array->Length(); i++) {\n ${localName}.push_back(${localName}Array->Get(i)->ToUint32()->Value());\n}", "${localName}") if ($type eq "octet[]"); if (IsWrapperType($type)) { my $wrapperType = IdlToWrapperType($type); if ($type =~ /.*Array$/ or $type =~ /^ArrayBuffer.*/) { return ("${wrapperType}* ${localName} = V8DOM::toClassPtr(${paramName}->ToObject()->GetInternalField(0))->nativeObj;", "${localName}"); } return ("${wrapperType}* ${localName} = V8DOM::toClassPtr(${paramName}->ToObject()->GetInternalField(0))->nativeObj;", "*${localName}"); } print $type."\n"; die(); } sub IdlToTypeChecker { my $idlType = shift; my $attr = shift; return $attr."->IsString()" if ($idlType eq "DOMString"); return $attr."->IsBoolean()" if ($idlType eq "boolean"); return $attr."->IsInt32()" if ($idlType eq "short"); return $attr."->IsInt32()" if ($idlType eq "long"); return $attr."->IsArray()" if ($idlType eq "long[]"); return $attr."->IsUint32()" if ($idlType eq "unsigned short"); return $attr."->IsUint32()" if ($idlType eq "unsigned long"); return $attr."->IsInt32()" if ($idlType eq "byte"); return $attr."->IsUint32()" if ($idlType eq "octet"); return $attr."->IsNumber()" if ($idlType eq "double"); return $attr."->IsArray()" if ($idlType eq "double[]"); return $attr."->IsNumber()" if ($idlType eq "float"); return $attr."->IsArray()" if ($idlType eq "float[]"); return $attr."->IsArray()" if ($idlType eq "short[]"); return $attr."->IsArray()" if ($idlType eq "unsigned short[]"); return $attr."->IsArray()" if ($idlType eq "unsigned long[]"); return $attr."->IsArray()" if ($idlType eq "byte[]"); return $attr."->IsArray()" if ($idlType eq "octet[]"); return "true" if ($idlType eq "any"); return $attr."->IsObject() && V8".$idlType."::hasInstance(".$attr.")" if (IsWrapperType($idlType)); print $idlType."\n"; die(); } sub IdlToWrapperAttrGetter { my $interface = shift; my $attribute = shift; return $attribute->signature->name if ($interface->name eq "NodeSet" && $attribute->signature->name eq "size"); return $attribute->signature->name if ($interface->name eq "NodeSet" && $attribute->signature->name eq "empty"); return "asString" if ($interface->name eq "XPathResult" && $attribute->signature->name eq "stringValue"); return "asBool" if ($interface->name eq "XPathResult" && $attribute->signature->name eq "booleanValue"); return "asNumber" if ($interface->name eq "XPathResult" && $attribute->signature->name eq "numberValue"); return "get" . ucfirst($attribute->signature->name); } sub IdlToWrapperFunction { my $interface = shift; my $function = shift; # if ($interface->name eq "NodeSet" && $function->signature->name eq "toDocumentOrder") { # print Dumper($interface); # print Dumper($function); # } return "to_document_order" if ($interface->name eq "NodeSet" && $function->signature->name eq "toDocumentOrder"); return $function->signature->name; } sub IdlToWrapperAttrSetter { my $idlAttr = shift; return "set" . ucfirst($idlAttr); } sub IsReadonly { my $attribute = shift; my $attrExt = $attribute->signature->extendedAttributes; return ($attribute->type =~ /readonly/ || $attrExt->{"V8ReadOnly"}) && !$attrExt->{"Replaceable"}; } my %non_wrapper_types = ( 'CompareHow' => 1, 'DOMObject' => 1, 'DOMString' => 1, 'DOMString[]' => 1, 'DOMTimeStamp' => 1, 'Date' => 1, 'Dictionary' => 1, 'EventListener' => 1, # FIXME: When EventTarget is an interface and not a mixin, fix this so that # EventTarget is treated as a wrapper type. 'EventTarget' => 1, 'IDBKey' => 1, 'JSObject' => 1, 'MediaQueryListListener' => 1, 'NodeFilter' => 1, 'any' => 1, 'boolean' => 1, 'double' => 1, 'float' => 1, 'int' => 1, 'long long' => 1, 'long' => 1, 'long[]' => 1, 'short' => 1, 'short[]' => 1, 'void' => 1, 'byte' => 1, 'byte[]' => 1, 'octet' => 1, 'char' => 1, 'float[]' => 1, 'float' => 1, 'double[]' => 1, 'octet[]' => 1, 'double' => 1, 'unsigned int' => 1, 'unsigned long long' => 1, 'unsigned long' => 1, 'unsigned long[]' => 1, 'unsigned short' => 1, 'unsigned short[]' => 1 ); sub IsWrapperType { my $type = shift; return !($non_wrapper_types{$type}); } sub GenerateHeaderContentHeader { my $interface = shift; my $v8InterfaceName = "V8" . $interface->name; my $conditionalString = $codeGenerator->GenerateConditionalString($interface); my @headerContentHeader = split("\r", $headerTemplate); push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString; push(@headerContentHeader, "\n#ifndef ${v8InterfaceName}" . "_h"); push(@headerContentHeader, "\n#define ${v8InterfaceName}" . "_h\n\n"); return @headerContentHeader; } 1;