[WebKit IDL] remove all module from idl files.
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / Bindings / CodeGeneratorTestRunner.pm
1 # Copyright (C) 2010 Apple Inc. All rights reserved.
2 # Copyright (C) 2012 Samsung Electronics
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 # 1. Redistributions of source code must retain the above copyright
8 #    notice, this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright
10 #    notice, this list of conditions and the following disclaimer in the
11 #    documentation and/or other materials provided with the distribution.
12 #
13 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 # THE POSSIBILITY OF SUCH DAMAGE.
24
25 use strict;
26 use warnings;
27 use File::Spec;
28
29 package CodeGeneratorTestRunner;
30
31 sub new
32 {
33     my ($class, $codeGenerator, $outputDir, $outputHeaderDir, $layerOnTop, $preprocessor, $writeDependencies, $verbose, $idlFilePath) = @_;
34
35     my $reference = {
36         codeGenerator => $codeGenerator,
37         outputDir => $outputDir,
38         idlFilePath => $idlFilePath,
39     };
40
41     bless($reference, $class);
42     return $reference;
43 }
44
45 sub GenerateModule
46 {
47 }
48
49 sub GenerateInterface
50 {
51     my ($self, $interface, $defines) = @_;
52
53     foreach my $file ($self->_generateHeaderFile($interface), $self->_generateImplementationFile($interface)) {
54         open(FILE, ">", File::Spec->catfile($$self{outputDir}, $$file{name})) or die "Failed to open $$file{name} for writing: $!";
55         print FILE @{$$file{contents}};
56         close(FILE) or die "Failed to close $$file{name} after writing: $!";
57     }
58 }
59
60 sub finish
61 {
62 }
63
64 sub _className
65 {
66     my ($idlType) = @_;
67
68     return "JS" . _implementationClassName($idlType);
69 }
70
71 sub _classRefGetter
72 {
73     my ($self, $idlType) = @_;
74     return $$self{codeGenerator}->WK_lcfirst(_implementationClassName($idlType)) . "Class";
75 }
76
77 sub _parseLicenseBlock
78 {
79     my ($fileHandle) = @_;
80
81     my ($copyright, $readCount, $buffer, $currentCharacter, $previousCharacter);
82     my $startSentinel = "/*";
83     my $lengthOfStartSentinel = length($startSentinel);
84     $readCount = read($fileHandle, $buffer, $lengthOfStartSentinel);
85     return "" if ($readCount < $lengthOfStartSentinel || $buffer ne $startSentinel);
86     $copyright = $buffer;
87
88     while ($readCount = read($fileHandle, $currentCharacter, 1)) {
89         $copyright .= $currentCharacter;
90         return $copyright if $currentCharacter eq "/" && $previousCharacter eq "*";
91         $previousCharacter = $currentCharacter;
92     }
93
94     return "";
95 }
96
97 sub _parseLicenseBlockFromFile
98 {
99     my ($path) = @_;
100     open my $fileHandle, "<", $path or die "Failed to open $path for reading: $!";
101     my $licenseBlock = _parseLicenseBlock($fileHandle);
102     close($fileHandle);
103     return $licenseBlock;
104 }
105
106 sub _defaultLicenseBlock
107 {
108     return <<EOF;
109 /*
110  * Copyright (C) 2010 Apple Inc. All rights reserved.
111  *
112  * Redistribution and use in source and binary forms, with or without
113  * modification, are permitted provided that the following conditions
114  * are met:
115  * 1. Redistributions of source code must retain the above copyright
116  *    notice, this list of conditions and the following disclaimer.
117  * 2. Redistributions in binary form must reproduce the above copyright
118  *    notice, this list of conditions and the following disclaimer in the
119  *    documentation and/or other materials provided with the distribution.
120  *
121  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
122  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
123  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
124  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
125  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
126  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
127  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
128  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
129  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
130  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
131  * THE POSSIBILITY OF SUCH DAMAGE.
132  */
133 EOF
134 }
135
136 sub _licenseBlock
137 {
138     my ($self) = @_;
139     return $self->{licenseBlock} if $self->{licenseBlock};
140
141     my $licenseBlock = _parseLicenseBlockFromFile($self->{idlFilePath}) || _defaultLicenseBlock();
142     $self->{licenseBlock} = $licenseBlock;
143     return $licenseBlock;
144 }
145
146 sub _generateHeaderFile
147 {
148     my ($self, $interface) = @_;
149
150     my @contents = ();
151
152     my $idlType = $interface->name;
153     my $className = _className($idlType);
154     my $implementationClassName = _implementationClassName($idlType);
155     my $filename = $className . ".h";
156
157     push(@contents, $self->_licenseBlock());
158
159     my $parentClassName = _parentClassName($interface);
160
161     push(@contents, <<EOF);
162
163 #ifndef ${className}_h
164 #define ${className}_h
165
166 #include "${parentClassName}.h"
167 EOF
168     push(@contents, <<EOF);
169
170 namespace WTR {
171
172 class ${implementationClassName};
173
174 class ${className} : public ${parentClassName} {
175 public:
176     static JSClassRef @{[$self->_classRefGetter($idlType)]}();
177
178 private:
179     static const JSStaticFunction* staticFunctions();
180     static const JSStaticValue* staticValues();
181 EOF
182
183     if (my @functions = @{$interface->functions}) {
184         push(@contents, "\n    // Functions\n\n");
185         foreach my $function (@functions) {
186             push(@contents, "    static JSValueRef @{[$function->signature->name]}(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);\n");
187         }
188     }
189
190     if (my @attributes = @{$interface->attributes}) {
191         push(@contents, "\n    // Attributes\n\n");
192         foreach my $attribute (@attributes) {
193             push(@contents, "    static JSValueRef @{[$self->_getterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef*);\n");
194             push(@contents, "    static bool @{[$self->_setterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef, JSValueRef*);\n") unless $attribute->type =~ /^readonly/;
195         }
196     }
197
198     push(@contents, <<EOF);
199 };
200     
201 ${implementationClassName}* to${implementationClassName}(JSContextRef, JSValueRef);
202
203 } // namespace WTR
204
205 #endif // ${className}_h
206 EOF
207
208     return { name => $filename, contents => \@contents };
209 }
210
211 sub _generateImplementationFile
212 {
213     my ($self, $interface) = @_;
214
215     my @contentsPrefix = ();
216     my %contentsIncludes = ();
217     my @contents = ();
218
219     my $idlType = $interface->name;
220     my $className = _className($idlType);
221     my $implementationClassName = _implementationClassName($idlType);
222     my $filename = $className . ".cpp";
223
224     push(@contentsPrefix, $self->_licenseBlock());
225
226     my $classRefGetter = $self->_classRefGetter($idlType);
227     my $parentClassName = _parentClassName($interface);
228
229     $contentsIncludes{"${className}.h"} = 1;
230     $contentsIncludes{"${implementationClassName}.h"} = 1;
231
232     push(@contentsPrefix, <<EOF);
233
234 EOF
235
236     push(@contents, <<EOF);
237 #include <JavaScriptCore/JSRetainPtr.h>
238 #include <wtf/GetPtr.h>
239
240 namespace WTR {
241
242 ${implementationClassName}* to${implementationClassName}(JSContextRef context, JSValueRef value)
243 {
244     if (!context || !value || !${className}::${classRefGetter}() || !JSValueIsObjectOfClass(context, value, ${className}::${classRefGetter}()))
245         return 0;
246     return static_cast<${implementationClassName}*>(JSWrapper::unwrap(context, value));
247 }
248
249 JSClassRef ${className}::${classRefGetter}()
250 {
251     static JSClassRef jsClass;
252     if (!jsClass) {
253         JSClassDefinition definition = kJSClassDefinitionEmpty;
254         definition.className = "${idlType}";
255         definition.parentClass = @{[$self->_parentClassRefGetterExpression($interface)]};
256         definition.staticValues = staticValues();
257         definition.staticFunctions = staticFunctions();
258 EOF
259
260     push(@contents, "        definition.initialize = initialize;\n") unless _parentInterface($interface);
261     push(@contents, "        definition.finalize = finalize;\n") unless _parentInterface($interface);
262
263     push(@contents, <<EOF);
264         jsClass = JSClassCreate(&definition);
265     }
266     return jsClass;
267 }
268
269 EOF
270
271     push(@contents, $self->_staticFunctionsGetterImplementation($interface), "\n");
272     push(@contents, $self->_staticValuesGetterImplementation($interface));
273
274     if (my @functions = @{$interface->functions}) {
275         push(@contents, "\n// Functions\n");
276
277         foreach my $function (@functions) {
278             push(@contents, <<EOF);
279
280 JSValueRef ${className}::@{[$function->signature->name]}(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
281 {
282     ${implementationClassName}* impl = to${implementationClassName}(context, thisObject);
283     if (!impl)
284         return JSValueMakeUndefined(context);
285
286 EOF
287             my $functionCall;
288             if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
289                 $functionCall = "impl->" . $function->signature->name . "(context, argumentCount, arguments, exception)";
290             } else {
291                 my @parameters = ();
292                 my @specifiedParameters = @{$function->parameters};
293
294                 $self->_includeHeaders(\%contentsIncludes, $function->signature->type, $function->signature);
295
296                 if ($function->signature->extendedAttributes->{"PassContext"}) {
297                     push(@parameters, "context");
298                 }
299
300                 foreach my $i (0..$#specifiedParameters) {
301                     my $parameter = $specifiedParameters[$i];
302
303                     $self->_includeHeaders(\%contentsIncludes, $idlType, $parameter);
304
305                     push(@contents, "    " . $self->_platformTypeVariableDeclaration($parameter, $parameter->name, "arguments[$i]", "argumentCount > $i") . "\n");
306                     
307                     push(@parameters, $self->_parameterExpression($parameter));
308                 }
309
310                 $functionCall = "impl->" . $function->signature->name . "(" . join(", ", @parameters) . ")";
311             }
312             
313             push(@contents, "    ${functionCall};\n\n") if $function->signature->type eq "void";
314             push(@contents, "    return " . $self->_returnExpression($function->signature, $functionCall) . ";\n}\n");
315         }
316     }
317
318     if (my @attributes = @{$interface->attributes}) {
319         push(@contents, "\n// Attributes\n");
320         foreach my $attribute (@attributes) {
321             $self->_includeHeaders(\%contentsIncludes, $attribute->signature->type, $attribute->signature);
322
323             my $getterName = $self->_getterName($attribute);
324             my $getterExpression = "impl->${getterName}()";
325
326             push(@contents, <<EOF);
327
328 JSValueRef ${className}::${getterName}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef* exception)
329 {
330     ${implementationClassName}* impl = to${implementationClassName}(context, object);
331     if (!impl)
332         return JSValueMakeUndefined(context);
333
334     return @{[$self->_returnExpression($attribute->signature, $getterExpression)]};
335 }
336 EOF
337
338             unless ($attribute->type =~ /^readonly/) {
339                 push(@contents, <<EOF);
340
341 bool ${className}::@{[$self->_setterName($attribute)]}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef value, JSValueRef* exception)
342 {
343     ${implementationClassName}* impl = to${implementationClassName}(context, object);
344     if (!impl)
345         return false;
346
347 EOF
348
349                 my $platformValue = $self->_platformTypeConstructor($attribute->signature, "value");
350
351                 push(@contents, <<EOF);
352     impl->@{[$self->_setterName($attribute)]}(${platformValue});
353
354     return true;
355 }
356 EOF
357             }
358         }
359     }
360
361     push(@contents, <<EOF);
362
363 } // namespace WTR
364
365 EOF
366
367     unshift(@contents, map { "#include \"$_\"\n" } sort keys(%contentsIncludes));
368     unshift(@contents, "#include \"config.h\"\n");
369     unshift(@contents, @contentsPrefix);
370
371     return { name => $filename, contents => \@contents };
372 }
373
374 sub _getterName
375 {
376     my ($self, $attribute) = @_;
377
378     my $signature = $attribute->signature;
379     my $name = $signature->name;
380
381     return $name;
382 }
383
384 sub _includeHeaders
385 {
386     my ($self, $headers, $idlType, $signature) = @_;
387
388     return unless defined $idlType;
389     return if $idlType eq "boolean";
390     return if $idlType eq "object";
391     return if $$self{codeGenerator}->IsNonPointerType($idlType);
392     return if $$self{codeGenerator}->IsStringType($idlType);
393
394     $$headers{_className($idlType) . ".h"} = 1;
395     $$headers{_implementationClassName($idlType) . ".h"} = 1;
396 }
397
398 sub _implementationClassName
399 {
400     my ($idlType) = @_;
401
402     return $idlType;
403 }
404
405 sub _parentClassName
406 {
407     my ($interface) = @_;
408
409     my $parentInterface = _parentInterface($interface);
410     return $parentInterface ? _className($parentInterface) : "JSWrapper";
411 }
412
413 sub _parentClassRefGetterExpression
414 {
415     my ($self, $interface) = @_;
416
417     my $parentInterface = _parentInterface($interface);
418     return $parentInterface ? $self->_classRefGetter($parentInterface) . "()" : "0";
419 }
420
421 sub _parentInterface
422 {
423     my ($interface) = @_;
424     return $interface->parents->[0];
425 }
426
427 sub _platformType
428 {
429     my ($self, $idlType, $signature) = @_;
430
431     return undef unless defined $idlType;
432
433     return "bool" if $idlType eq "boolean";
434     return "JSValueRef" if $idlType eq "object";
435     return "JSRetainPtr<JSStringRef>" if $$self{codeGenerator}->IsStringType($idlType);
436     return "double" if $$self{codeGenerator}->IsNonPointerType($idlType);
437     return _implementationClassName($idlType);
438 }
439
440 sub _platformTypeConstructor
441 {
442     my ($self, $signature, $argumentName) = @_;
443
444     my $idlType = $signature->type;
445
446     return "JSValueToBoolean(context, $argumentName)" if $idlType eq "boolean";
447     return "$argumentName" if $idlType eq "object";
448     return "JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, $argumentName, 0))" if $$self{codeGenerator}->IsStringType($idlType);
449     return "JSValueToNumber(context, $argumentName, 0)" if $$self{codeGenerator}->IsNonPointerType($idlType);
450     return "to" . _implementationClassName($idlType) . "(context, $argumentName)";
451 }
452
453 sub _platformTypeVariableDeclaration
454 {
455     my ($self, $signature, $variableName, $argumentName, $condition) = @_;
456
457     my $platformType = $self->_platformType($signature->type, $signature);
458     my $constructor = $self->_platformTypeConstructor($signature, $argumentName);
459
460     my %nonPointerTypes = (
461         "bool" => 1,
462         "double" => 1,
463         "JSRetainPtr<JSStringRef>" => 1,
464         "JSValueRef" => 1,
465     );
466
467     my $nullValue = "0";
468     if ($platformType eq "JSValueRef") {
469         $nullValue = "JSValueMakeUndefined(context)";
470     } elsif (defined $nonPointerTypes{$platformType} && $platformType ne "double") {
471         $nullValue = "$platformType()";
472     }
473
474     $platformType .= "*" unless defined $nonPointerTypes{$platformType};
475
476     return "$platformType $variableName = $condition && $constructor;" if $condition && $platformType eq "bool";
477     return "$platformType $variableName = $condition ? $constructor : $nullValue;" if $condition;
478     return "$platformType $variableName = $constructor;";
479 }
480
481 sub _returnExpression
482 {
483     my ($self, $signature, $expression) = @_;
484
485     my $returnIDLType = $signature->type;
486
487     return "JSValueMakeUndefined(context)" if $returnIDLType eq "void";
488     return "JSValueMakeBoolean(context, ${expression})" if $returnIDLType eq "boolean";
489     return "${expression}" if $returnIDLType eq "object";
490     return "JSValueMakeNumber(context, ${expression})" if $$self{codeGenerator}->IsNonPointerType($returnIDLType);
491     return "JSValueMakeStringOrNull(context, ${expression}.get())" if $$self{codeGenerator}->IsStringType($returnIDLType);
492     return "toJS(context, WTF::getPtr(${expression}))";
493 }
494
495 sub _parameterExpression
496 {
497     my ($self, $parameter) = @_;
498
499     my $idlType = $parameter->type;
500     my $name = $parameter->name;
501
502     return "${name}.get()" if $$self{codeGenerator}->IsStringType($idlType);
503     return $name;
504 }
505
506 sub _setterName
507 {
508     my ($self, $attribute) = @_;
509
510     my $name = $attribute->signature->name;
511
512     return "set" . $$self{codeGenerator}->WK_ucfirst($name);
513 }
514
515 sub _staticFunctionsGetterImplementation
516 {
517     my ($self, $interface) = @_;
518
519     my $mapFunction = sub {
520         my $name = $_->signature->name;
521         my @attributes = qw(kJSPropertyAttributeDontDelete kJSPropertyAttributeReadOnly);
522         push(@attributes, "kJSPropertyAttributeDontEnum") if $_->signature->extendedAttributes->{"DontEnum"};
523
524         return  "{ \"$name\", $name, " . join(" | ", @attributes) . " }";
525     };
526
527     return $self->_staticFunctionsOrValuesGetterImplementation($interface, "function", "{ 0, 0, 0 }", $mapFunction, $interface->functions);
528 }
529
530 sub _staticFunctionsOrValuesGetterImplementation
531 {
532     my ($self, $interface, $functionOrValue, $arrayTerminator, $mapFunction, $functionsOrAttributes) = @_;
533
534     my $className = _className($interface->name);
535     my $uppercaseFunctionOrValue = $$self{codeGenerator}->WK_ucfirst($functionOrValue);
536
537     my $result = <<EOF;
538 const JSStatic${uppercaseFunctionOrValue}* ${className}::static${uppercaseFunctionOrValue}s()
539 {
540 EOF
541
542     my @initializers = map(&$mapFunction, @{$functionsOrAttributes});
543     return $result . "    return 0;\n}\n" unless @initializers;
544
545     $result .= <<EOF
546     static const JSStatic${uppercaseFunctionOrValue} ${functionOrValue}s[] = {
547         @{[join(",\n        ", @initializers)]},
548         ${arrayTerminator}
549     };
550     return ${functionOrValue}s;
551 }
552 EOF
553 }
554
555 sub _staticValuesGetterImplementation
556 {
557     my ($self, $interface) = @_;
558
559     my $mapFunction = sub {
560         return if $_->signature->extendedAttributes->{"NoImplementation"};
561
562         my $attributeName = $_->signature->name;
563         my $attributeIsReadonly = $_->type =~ /^readonly/;
564         my $getterName = $self->_getterName($_);
565         my $setterName = $attributeIsReadonly ? "0" : $self->_setterName($_);
566         my @attributes = qw(kJSPropertyAttributeDontDelete);
567         push(@attributes, "kJSPropertyAttributeReadOnly") if $attributeIsReadonly;
568         push(@attributes, "kJSPropertyAttributeDontEnum") if $_->signature->extendedAttributes->{"DontEnum"};
569
570         return "{ \"$attributeName\", $getterName, $setterName, " . join(" | ", @attributes) . " }";
571     };
572
573     return $self->_staticFunctionsOrValuesGetterImplementation($interface, "value", "{ 0, 0, 0, 0 }", $mapFunction, $interface->attributes);
574 }
575
576 1;