# 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 CodeGeneratorArabicaJSC; use strict; use Data::Dumper; use Carp qw/longmess cluck confess/; use constant FileNamePrefix => "JSC"; my $codeGenerator; my @headerContent = (); my @implContentHeader = (); my @implContent = (); my @implContentDecls = (); my %implIncludes = (); my %headerIncludes = (); # Default .h template my $headerTemplate = << "EOF"; /* This file is part of the Wrapper 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; bless($reference, $object); return $reference; } sub GenerateInterface { my $object = shift; my $interface = shift; # 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 "JSCbool.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($interface); # 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{"uscxml/plugins/datamodel/ecmascript/JavaScriptCore/JSCDOM.h"} = 1; $headerIncludes{"DOM/Node.hpp"} = 1; $headerIncludes{"JavaScriptCore/JavaScriptCore.h"} = 1; if ($interfaceName =~ /.*Array$/ or $interfaceName =~ /^ArrayBuffer.*/) { $headerIncludes{"../../TypedArray.h"} = 1; } foreach (@{$interface->parents}) { my $parent = $_; $headerIncludes{"JSC${parent}.h"} = 1; } push(@headerContent, "#include \\n"); foreach my $headerInclude (sort keys(%headerIncludes)) { if ($headerInclude =~ /wtf|JavaScriptCore\/JavaScriptCore\.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 JSC${interfaceName} {"); push(@headerContent, "\npublic:"); my $wrapperType = IdlToWrapperType($interfaceName); push(@headerContent, <{'DontDestroyWrapped'}) { push(@headerContent, "\n JSC_DESTRUCTOR_KEEP_WRAPPED(JSC${interfaceName}Private);"); } else { push(@headerContent, "\n JSC_DESTRUCTOR(JSC${interfaceName}Private);"); } 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 JSValueRef ${name}${custom}Callback(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObj, size_t argumentCount, const JSValueRef* arguments, JSValueRef* exception);"); $generated{"${name}${custom}Callback"} = 1; } push(@headerContent, "\n"); if ($extensions->{'Constructors'}) { push(@headerContent, "\n static JSObjectRef jsConstructor(JSContextRef ctx, JSObjectRef constructor, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);"); } # 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 JSValueRef ${name}${customGetter}AttrGetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception);"); if (!IsReadonly($attribute)) { push(@headerContent, "\n static bool ${name}${customSetter}AttrSetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef value, JSValueRef* exception);"); } } # const getters foreach my $constant (@{$interface->constants}) { my $name = $constant->name; my $value = $constant->value; my $getter = "${name}ConstGetter"; push(@headerContent, "\n static JSValueRef ${getter}(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef* exception);"); } if ($extensions->{'CustomIndexedGetter'}) { push(@headerContent, "\n static bool hasPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName);"); push(@headerContent, "\n static JSValueRef getPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);"); } if ($extensions->{'CustomIndexedSetter'}) { push(@headerContent, "\n static bool setPropertyCustomCallback(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception);"); } push(@headerContent, "\n"); push(@headerContent, <{'CustomIndexedGetter'}) { push(@headerContent, " classDef.hasProperty = hasPropertyCustomCallback;\n"); push(@headerContent, " classDef.getProperty = getPropertyCustomCallback;\n"); } if ($extensions->{'CustomIndexedSetter'}) { push(@headerContent, " classDef.setProperty = setPropertyCustomCallback;\n"); } if ($extensions->{'Constructors'}) { push(@headerContent, " classDef.callAsConstructor = jsConstructor;\n"); } if (@{$interface->parents}) { my $parent = @{$interface->parents}[0]; push(@headerContent, " classDef.parentClass = JSC${parent}::getTmpl();\n"); } push(@headerContent, <name; my $extensions = $interface->extendedAttributes; push(@implContent, "\nJSStaticValue JSC${interfaceName}::staticValues[] = {"); 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 = "${name}${customGetter}AttrGetter"; my $setter = (IsReadonly($attribute) ? "0" : "${name}${customSetter}AttrSetter"); my $flags = "kJSPropertyAttributeDontDelete"; $flags .= " | kJSPropertyAttributeReadOnly" if (IsReadonly($attribute)); push(@implContent, "\n { \"${name}\", ${getter}, ${setter}, ${flags} },"); } push(@implContent, "\n"); foreach my $constant (@{$interface->constants}) { my $name = $constant->name; my $value = $constant->value; my $getter = "${name}ConstGetter"; my $flags = "kJSPropertyAttributeDontDelete | kJSPropertyAttributeReadOnly"; push(@implContent, "\n { \"${name}\", ${getter}, 0, ${flags} },"); } push(@implContent, "\n { 0, 0, 0, 0 }"); push(@implContent, "\n};\n"); push(@implContent, "\nJSStaticFunction JSC${interfaceName}::staticFunctions[] = {"); my %generated; foreach my $function (@{$interface->functions}) { my $name = $function->signature->name; my $attrExt = $function->signature->extendedAttributes; my $custom = ($attrExt->{'Custom'} ? "Custom" : ""); my $callback = ${name}.${custom}."Callback"; my $flags = "kJSPropertyAttributeDontDelete"; next if (exists $generated{"${name}"}); $generated{"${name}"} = 1; push(@implContent, "\n { \"${name}\", ${callback}, ${flags} },"); } push(@implContent, "\n { 0, 0, 0 }"); push(@implContent, "\n};\n"); } 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, <nativeObj->${wrapperGetter}")); push(@implContent, <nativeObj->${wrapperGetter}); JSClassRef arbaicaRetClass = JSC${attrType}::getTmpl(); struct JSC${attrType}::JSC${attrType}Private* retPrivData = new JSC${attrType}::JSC${attrType}Private(); retPrivData->dom = privData->dom; retPrivData->nativeObj = arabicaRet; JSObjectRef arbaicaRetObj = JSObjectMake(ctx, arbaicaRetClass, retPrivData); return arbaicaRetObj; END } else { my $JSCType = IdlToJSCType($attrType); if ($JSCType eq "String") { if ($attrExt->{'EmptyAsNull'}) { push(@implContent, "\n if (privData->nativeObj->${wrapperGetter}.length() == 0)"); push(@implContent, "\n return JSValueMakeUndefined(ctx);"); } push(@implContent, <nativeObj->${wrapperGetter}.c_str()); JSValueRef retVal = JSValueMakeString(ctx, stringRef); JSStringRelease(stringRef); return retVal; END } elsif($JSCType eq "Number") { push(@implContent, "\n return JSValueMakeNumber(ctx, privData->nativeObj->${wrapperGetter});\n"); } elsif($JSCType eq "Boolean") { push(@implContent, "\n return JSValueMakeBoolean(ctx, privData->nativeObj->${wrapperGetter});\n"); } } push(@implContent, " }\n\n"); } if (!$attrExt->{'CustomSetter'}) { # setter if (!IsReadonly($attribute)) { push(@implContent, "\n bool JSC${interfaceName}::${attrName}AttrSetter(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) {"); push(@implContent, "\n struct JSC${interfaceName}Private* privData = (struct JSC${interfaceName}Private*)JSObjectGetPrivate(thisObj);\n"); my $wrapperSetter = IdlToWrapperAttrSetter($attrName); my ($handle, $deref) = IdlToArgHandle($attribute->signature->type, "local".ucfirst($attribute->signature->name), "value"); push(@implContent, "\n $handle"); push(@implContent, "\n privData->nativeObj->${wrapperSetter}(${deref});"); push(@implContent, "\n return true;"); push(@implContent, "\n }\n"); } } } foreach my $constant (@{$interface->constants}) { my $name = $constant->name; my $value = $constant->value; my $getter = "${name}ConstGetter"; push(@implContent, " JSValueRef JSC${interfaceName}::${getter}(JSContextRef ctx, JSObjectRef thisObj, JSStringRef propertyName, JSValueRef *exception) {"); my $JSCType = IdlToJSCType($constant->type); if ($JSCType eq "String") { push(@implContent, "\n JSStringRef jscString = JSStringCreateWithUTF8CString(" . $constant->value . ");". "\n JSValueRef retVal = JSValueMakeString(ctx, jscString);". "\n JSStringRelease(jscString);". "\n return retVal;\n"); } elsif($JSCType eq "Number") { push(@implContent, "\n return JSValueMakeNumber(ctx, " . $constant->value . ");\n"); } elsif($JSCType eq "Boolean") { push(@implContent, "\n return JSValueMakeBoolean(ctx, " . $constant->value . ");\n"); } push(@implContent, <signature->type eq "NamedNodeMap"); return "" if ($attribute->signature->type eq "NodeList"); return "if (!$getterExpression) return JSValueMakeUndefined(ctx);"; } sub GenerateConstructor { my $interface = shift; my $interfaceName = $interface->name; my $extensions = $interface->extendedAttributes; my $wrapperType = IdlToWrapperType($interfaceName); if ($extensions->{'Constructors'}) { 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 (argumentCount == " . @{$constructor}); for (my $i = 0; $i < @{$constructor}; $i++) { my $type = $constructor->[$i]->{'domSignature::type'}; AddToImplIncludes("JSC".$type.".h") if (IsWrapperType($type)); push(@implContent, " &&\n " . IdlToTypeChecker($type, "arguments[$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), "arguments[$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, <nativeObj = localInstance; JSObjectRef retObj = JSObjectMake(ctx, retClass, retPrivData); return retObj; } END } } sub IdlToTypeChecker { my $idlType = shift; my $attr = shift; return "JSValueIsString(ctx, ${attr})" if ($idlType eq "DOMString"); return "JSValueIsBoolean(ctx, ${attr})" if ($idlType eq "boolean"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "short"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "long"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "long[]"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "unsigned short"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "unsigned long"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "byte"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "octet"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "double"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "double[]"); return "JSValueIsNumber(ctx, ${attr})" if ($idlType eq "float"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "float[]"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "short[]"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "unsigned short[]"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "unsigned long[]"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "byte[]"); return "JSValueIsObject(ctx, ${attr})" if ($idlType eq "octet[]"); return "true" if ($idlType eq "any"); return "JSValueIsObject(ctx, ${attr}) && JSValueIsObjectOfClass(ctx, ${attr}, JSC${idlType}::getTmpl())" if (IsWrapperType($idlType)); print $idlType."\n"; die(); } sub GenerateImplementationFunctionCallbacks { my $interface = shift; my $interfaceName = $interface->name; my $wrapperType = IdlToWrapperType($interfaceName); # 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, <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 (argumentCount == " . @{$variant}); for (my $i = 0; $i < @{$variant}; $i++) { my $type = $variant->[$i]->{'domSignature::type'}; push(@implContent, " &&\n " . IdlToTypeChecker($type, "arguments[$i]")); } push(@implContent, ")\n {"); foreach my $parameter (@{$variant}) { my $type = $parameter->type; AddToImplIncludes("JSC".$type.".h") if (IsWrapperType($type)); my ($handle, $deref) = IdlToArgHandle($parameter->type, "local".ucfirst($parameter->name), "arguments[${parameterIndex}]"); push(@implContent, "\n ${handle}"); # push(@implContent, "\n if (exception)\n return JSValueMakeUndefined(ctx);"); 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("JSC".$retType.".h"); push(@implContent, <dom = privData->dom; retPrivData->nativeObj = retVal; JSObjectRef retObj = JSObjectMake(ctx, retClass, retPrivData); return retObj; END } else { my $toHandleString = NativeToHandle($retNativeType, "retVal", "jscRetVal"); push(@implContent, "${toHandleString}\n return jscRetVal;"); } } push(@implContent, <name; my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface); my $JSCInterfaceName = "JSC$interfaceName"; my $wrapperType = IdlToWrapperType($interfaceName); AddToImplIncludes("JSC${interfaceName}.h"); # Find the super descriptor. my $parentClass = ""; my $parentClassTemplate = ""; foreach (@{$interface->parents}) { my $parent = $_; AddToImplIncludes("JSC${parent}.h"); $parentClass = "JSC" . $parent; last; } push(@implContent, "namespace Arabica {\n"); push(@implContent, "namespace DOM {\n\n"); push(@implContent, "JSClassRef JSC${interfaceName}::Tmpl;\n"); GenerateClassDefStatics($interface); if ($interface->extendedAttributes->{'Constructors'}) { GenerateConstructor($interface); } GenerateImplementationAttributes($interface); GenerateImplementationFunctionCallbacks($interface); push(@implContent, <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 = 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 IdlToJSCType { my $idlType = shift; return "Number" if ($idlType eq "unsigned short"); return "Number" if ($idlType eq "short"); return "Number" if ($idlType eq "unsigned long"); return "Number" if ($idlType eq "long"); return "String" if ($idlType eq "DOMString"); return "Boolean" if ($idlType eq "boolean"); return "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; my $paramName = shift; return ("\n JSValueRef ${paramName} = JSValueMakeBoolean(ctx, ${nativeName});") if ($nativeType eq "bool"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "double"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "float"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "short"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "char"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "unsigned char"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "unsigned short"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "unsigned long"); return ("\n JSValueRef ${paramName} = JSValueMakeNumber(ctx, ${nativeName});") if ($nativeType eq "long"); return ("\n JSValueRef ${paramName} = JSValueMakeUndefined(ctx);") if ($nativeType eq "void"); return ( "\n JSStringRef jscString = JSStringCreateWithUTF8CString(${nativeName}.c_str());". "\n JSValueRef ${paramName} = JSValueMakeString(ctx, jscString);". "\n JSStringRelease(jscString);" ) if ($nativeType eq "std::string"); 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; if ($type eq "DOMString") { return ( "JSStringRef stringRef${localName} = JSValueToStringCopy(ctx, ${paramName}, exception);\n" . "\t\tsize_t ${localName}MaxSize = JSStringGetMaximumUTF8CStringSize(stringRef${localName});\n" . "\t\tchar* ${localName}Buffer = new char[${localName}MaxSize];\n" . "\t\tJSStringGetUTF8CString(stringRef${localName}, ${localName}Buffer, ${localName}MaxSize);\n" . "\t\tstd::string ${localName}(${localName}Buffer);\n" . "\t\tJSStringRelease(stringRef${localName});\n" . "\t\tfree(${localName}Buffer);\n", "${localName}") ; } return ("unsigned long ${localName} = (unsigned long)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "unsigned long"); return ("long ${localName} = (long)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "long"); return ("unsigned short ${localName} = (unsigned short)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "unsigned short"); return ("float ${localName} = (float)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "float"); return ("double ${localName} = (double)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "double"); return ("short ${localName} = (short)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "short"); return ("char ${localName} = (char)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "byte"); return ("unsigned char ${localName} = (unsigned char)JSValueToNumber(ctx, ${paramName}, exception);", ${localName}) if ($type eq "octet"); return ("bool ${localName} = JSValueToBoolean(ctx, ${paramName});", ${localName}) if ($type eq "boolean"); return ("void* ${localName} = JSObjectGetPrivate(JSValueToObject(ctx, ${paramName}, exception));", ${localName}) if ($type eq "any"); if ($type =~ /(.*)\[\]$/) { my $nativeType = $1; $nativeType = "char" if ($nativeType =~ /^byte$/); $nativeType = "unsigned char" if ($nativeType =~ /^octet$/); return ("\ std::vector<${nativeType}> ${localName};\n\ JSValueRef ${localName}Item; unsigned int ${localName}Index = 0; while((${localName}Item = JSObjectGetPropertyAtIndex(ctx, JSValueToObject(ctx, ${paramName}, exception), ${localName}Index, exception))) {\ if (JSValueIsUndefined(ctx, ${localName}Item))\ break;\ if (JSValueIsNumber(ctx,${localName}Item))\ ${localName}.push_back(JSValueToNumber(ctx, ${localName}Item, exception));\ ${localName}Index++;\ }", "${localName}"); } # 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 ($wrapperType =~ /^Arabica.*/) { return ("${wrapperType}* ${localName} = ((struct JSC${type}::JSC${type}Private*)JSObjectGetPrivate(JSValueToObject(ctx, ${paramName}, exception)))->nativeObj;", "*${localName}"); } else { return ("${wrapperType}* ${localName} = ((struct JSC${type}::JSC${type}Private*)JSObjectGetPrivate(JSValueToObject(ctx, ${paramName}, exception)))->nativeObj;", "${localName}"); } } print $type."\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->{"JSCReadOnly"}) && !$attrExt->{"Replaceable"}; } sub GenerateArgumentsCountCheck { my $function = shift; my $interface = shift; my $numMandatoryParams = 0; my $allowNonOptional = 1; foreach my $param (@{$function->parameters}) { if ($param->extendedAttributes->{"Optional"} or $param->isVariadic) { $allowNonOptional = 0; } else { die "An argument must not be declared to be optional unless all subsequent arguments to the operation are also optional." if !$allowNonOptional; $numMandatoryParams++; } } my $argumentsCountCheckString = ""; if ($numMandatoryParams >= 1) { $argumentsCountCheckString .= " if (argumentCount < $numMandatoryParams) {\n". " std::string errorMsg = \"Wrong number of arguments in " . $function->signature->name . "\";\n" . " JSStringRef string = JSStringCreateWithUTF8CString(errorMsg.c_str());\n". " JSValueRef exceptionString =JSValueMakeString(ctx, string);\n". " JSStringRelease(string);\n". " *exception = JSValueToObject(ctx, exceptionString, NULL);\n". " return NULL;\n". " }\n"; } return $argumentsCountCheckString; } sub GenerateArgumentsTypeCheck { my $function = shift; my $interface = shift; my @andExpression = (); my $parameterIndex = 0; foreach my $parameter (@{$function->parameters}) { my $value = "arguments[$parameterIndex]"; my $type = $parameter->type; # Only DOMString or wrapper types are checked. # For DOMString with StrictTypeChecking only Null, Undefined and Object # are accepted for compatibility. Otherwise, no restrictions are made to # match the non-overloaded behavior. # FIXME: Implement WebIDL overload resolution algorithm. if ($codeGenerator->IsStringType($type)) { if ($parameter->extendedAttributes->{"StrictTypeChecking"}) { push(@andExpression, "(${value}->IsNull() || ${value}->IsUndefined() || ${value}->IsString() || ${value}->IsObject())"); } } elsif ($parameter->extendedAttributes->{"Callback"}) { # For Callbacks only checks if the value is null or object. push(@andExpression, "(${value}->IsNull() || ${value}->IsFunction())"); } elsif ($codeGenerator->IsArrayType($type) || $codeGenerator->GetSequenceType($type)) { if ($parameter->isNullable) { push(@andExpression, "(${value}->IsNull() || ${value}->IsArray())"); } else { push(@andExpression, "(${value}->IsArray())"); } } elsif (IsWrapperType($type)) { if ($parameter->isNullable) { push(@andExpression, "(${value}->IsNull() || JSC${type}::hasInstance($value))"); } else { push(@andExpression, "(JSC${type}::hasInstance($value))"); } } $parameterIndex++; } my $res = join(" && ", @andExpression); $res = "($res)" if @andExpression > 1; return $res; } 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, 'SerializedScriptValue' => 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, 'octet' => 1, 'char' => 1, 'float[]' => 1, 'byte[]' => 1, 'float' => 1, 'double[]' => 1, 'double' => 1, 'unsigned int' => 1, 'unsigned long long' => 1, 'unsigned long' => 1, 'unsigned long[]' => 1, 'unsigned short' => 1, 'unsigned short[]' => 1, 'octet[]' => 1 ); sub IsWrapperType { my $type = shift; return !($non_wrapper_types{$type}); } sub GenerateHeaderContentHeader { my $interface = shift; my $JSCInterfaceName = "JSC" . $interface->name; my $conditionalString = $codeGenerator->GenerateConditionalString($interface); my @headerContentHeader = split("\r", $headerTemplate); push(@headerContentHeader, "\n#if ${conditionalString}\n") if $conditionalString; push(@headerContentHeader, "\n#ifndef ${JSCInterfaceName}" . "_h"); push(@headerContentHeader, "\n#define ${JSCInterfaceName}" . "_h\n\n"); return @headerContentHeader; } 1;