Reviewed by Tim Hatcher.
[WebKit-https.git] / WebCore / bindings / scripts / CodeGeneratorObjC.pm
1
2 # Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
3 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com> 
4 # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
5 # Copyright (C) 2006 Apple Computer, Inc.
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Library General Public
9 # License as published by the Free Software Foundation; either
10 # version 2 of the License, or (at your option) any later version.
11
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # Library General Public License for more details.
16
17 # You should have received a copy of the GNU Library General Public License
18 # aint with this library; see the file COPYING.LIB.  If not, write to
19 # the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 # Boston, MA 02111-1307, USA.
21 #
22
23 package CodeGeneratorObjC;
24
25 use File::stat;
26
27 my $module = "";
28 my $outputDir = "";
29 my %implIncludes = ();
30 my %headerForwardDeclarations = ();
31 my %headerForwardDeclarationsForProtocols = ();
32
33 my $exceptionInit = "WebCore::ExceptionCode ec = 0;";
34 my $exceptionRaiseOnError = "raiseOnDOMError(ec);";
35
36 # Default Licence Templates
37 my $headerLicenceTemplate = << "EOF";
38 /*
39  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
40  * Copyright (C) 2006 Samuel Weinig <sam.weinig\@gmail.com>
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  *
51  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
52  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
55  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
58  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
59  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
61  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
62  */
63 EOF
64
65 my $implementationLicenceTemplate = << "EOF";
66 /*
67     This file is part of the WebKit open source project.
68     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
69
70     This library is free software; you can redistribute it and/or
71     modify it under the terms of the GNU Library General Public
72     License as published by the Free Software Foundation; either
73     version 2 of the License, or (at your option) any later version.
74
75     This library is distributed in the hope that it will be useful,
76     but WITHOUT ANY WARRANTY; without even the implied warranty of
77     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
78     Library General Public License for more details.
79
80     You should have received a copy of the GNU Library General Public License
81     along with this library; see the file COPYING.LIB.  If not, write to
82     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
83     Boston, MA 02111-1307, USA.
84 */
85 EOF
86
87 # Default constructor
88 sub new
89 {
90     my $object = shift;
91     my $reference = { };
92
93     $codeGenerator = shift;
94     $outputDir = shift;
95
96     bless($reference, $object);
97     return $reference;
98 }
99
100 sub finish
101 {
102     my $object = shift;
103
104     # Commit changes!
105     $object->WriteData();
106 }
107
108 # Params: 'domClass' struct
109 sub GenerateInterface
110 {
111     my $object = shift;
112     my $dataNode = shift;
113
114     $object->RemoveExcludedAttributesAndFunctions($dataNode);
115
116     # Start actual generation..
117     $object->GenerateHeader($dataNode);
118     $object->GenerateImplementation($dataNode);
119
120     my $name = $dataNode->name;
121
122     # Open files for writing...
123     my $headerFileName = "$outputDir/DOM$name.h";
124     my $implFileName = "$outputDir/DOM$name.mm";
125
126     open($IMPL, ">$implFileName") or die "Couldn't open file $implFileName";
127     open($HEADER, ">$headerFileName") or die "Couldn't open file $headerFileName";
128 }
129
130 # Params: 'idlDocument' struct
131 sub GenerateModule
132 {
133     my $object = shift;
134     my $dataNode = shift;  
135     
136     $module = $dataNode->module;    
137 }
138
139 sub RemoveExcludedAttributesAndFunctions
140 {
141     my $object = shift;
142     my $dataNode = shift;
143
144     my $i = 0;
145
146     while ($i < @{$dataNode->attributes}) {
147         my $lang = ${$dataNode->attributes}[$i]->signature->extendedAttributes->{"Exclude"};
148         if ($lang and $lang eq "ObjC") {
149             splice(@{$dataNode->attributes}, $i, 1);
150         } else {
151             $i++;
152         }
153     }
154
155     $i = 0;
156     while ($i < @{$dataNode->functions}) {
157         my $lang = ${$dataNode->functions}[$i]->signature->extendedAttributes->{"Exclude"};
158         if ($lang and $lang eq "ObjC") {
159             splice(@{$dataNode->functions}, $i, 1);
160         } else {
161             $i++;
162         }
163     }
164 }
165
166 sub GetClassName
167 {
168     my $name = $codeGenerator->StripModule(shift);
169     
170     # special cases
171     if ($name eq "boolean") {
172         return "BOOL";
173     } elsif ($name eq "unsigned long") {
174         return "unsigned";
175     } elsif ($name eq "long") {
176         return "int";
177     } elsif ($name eq "DOMString") {
178         return "NSString";
179     } elsif ($name eq "DOMWindow") {
180         return "DOMAbstractView";
181     } elsif ($name eq "XPathNSResolver") {
182         return "id <DOMXPathNSResolver>";
183     } elsif ($name eq "unsigned short" 
184              or $name eq "float"
185              or $name eq "void"
186              or $name eq "DOMImplementation") {
187         return $name;
188     }
189
190     # Default, assume Objective-C type has the same type name as
191     # idl type prefixed with "DOM".
192     return "DOM" . $name;
193 }
194
195 sub GetImplClassName
196 {
197     my $name = $codeGenerator->StripModule(shift);
198     
199     # special cases
200     if ($name eq "DOMImplementation") {
201         return "WebCore::DOMImplementationFront";
202     }
203
204     return "WebCore::" . $name;
205 }
206
207 sub GetParentImplClassName
208 {
209     my $dataNode = shift;
210
211     if (@{$dataNode->parents} eq 0) {
212         return "Object";
213     }
214
215     my $parent = $codeGenerator->StripModule($dataNode->parents(0));
216     
217     # special cases
218     if ($parent eq "EventTargetNode") {
219         $parent = "Node";
220     } elsif ($parent eq "HTMLCollection") {
221         $parent = "Object";
222     }
223
224     return $parent;
225 }
226
227 sub GetObjCType
228 {
229     my $name = GetClassName(shift);
230
231     if ($codeGenerator->IsPrimitiveType($name)
232             or $name eq "BOOL"
233             or $name eq "unsigned"
234             or $name eq "int"
235             or $name eq "id <DOMXPathNSResolver>") {
236         return $name;
237     }
238
239     # Default, return type as a pointer.
240     return "$name *";
241 }
242
243 sub GetObjCTypeMaker
244 {
245     my $type = $codeGenerator->StripModule(shift);
246
247     if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMString") {
248         return "";
249     }
250
251     if ($type eq "DOMRGBColor") {
252         return "_RGBColorWithRGB";
253     }
254
255     my $typeMaker = "";
256
257     if ($type eq "HTMLCollection") {
258         $typeMaker = "collection";
259     } elsif ($type eq "HTMLFormElement") {
260         $typeMaker = "formElement";
261     } elsif ($type eq "HTMLDocument") {
262         $typeMaker = "HTMLDocument";
263     } elsif ($type eq "CSSStyleDeclaration") {
264         $typeMaker = "styleDeclaration";
265     } elsif ($type eq "CSSStyleSheet") {
266         $typeMaker = "CSSStyleSheet";
267     } elsif ($type eq "DOMImplementation") {
268         $typeMaker = "DOMImplementation";
269     } elsif ($type eq "CDATASection") {
270         $typeMaker = "CDATASection";
271     } elsif ($type eq "DOMWindow") {
272         $typeMaker = "abstractView";
273     } elsif ($type eq "XPathResult") {
274         $typeMaker = "xpathResult";
275     } elsif ($type eq "XPathNSResolver") {
276         $typeMaker = "xpathNSResolver";
277     } elsif ($type eq "XPathExpression") {
278         $typeMaker = "xpathExpression";
279     } else {
280         $typeMaker = lcfirst($type);
281     }
282
283     # put into the form "_fooBarWith" for type FooBar.
284     $typeMaker = "_" . $typeMaker . "With";
285     return $typeMaker;
286 }
287
288 sub AddForwardDeclarationsForType
289 {
290     my $type = $codeGenerator->StripModule(shift);
291     
292     if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMString") {
293         return;
294     }
295     
296     if ($type eq "DOMImplementation") {
297         $headerForwardDeclarations{"$type"} = 1;
298         return;
299     }
300
301     if ($type eq "DOMWindow") {
302         $headerForwardDeclarations{"DOMAbstractView"} = 1;
303         return;
304     }
305
306     if ($type eq "XPathNSResolver") {
307         # Only one protocol so far.
308         $headerForwardDeclarationsForProtocols{"DOMXPathNSResolver"} = 1;
309         return;
310     }
311
312     $headerForwardDeclarations{"DOM$type"} = 1;
313 }
314
315 sub AddIncludesForType
316 {
317     my $type = $codeGenerator->StripModule(shift);
318     
319     if ($codeGenerator->IsPrimitiveType($type)) {
320         return;
321     }
322
323     if ($type eq "DOMString") {
324         $implIncludes{"PlatformString.h"} = 1;
325         return;
326     }
327
328     # Temp DOMCSS.h
329     if ($type eq "Counter"
330             or $type eq "MediaList"
331             or $type eq "CSSStyleSheet") {
332         $implIncludes{"DOMCSS.h"} = 1;
333         $implIncludes{"$type.h"} = 1;
334         return;
335     }
336     if ($type eq "CSSStyleDeclaration") {
337         $implIncludes{"DOMCSS.h"} = 1;
338         $implIncludes{"$type.h"} = 1;
339         $implIncludes{"CSSMutableStyleDeclaration.h"} = 1;
340         return;
341     }
342     if ($type eq "RGBColor" or $type eq "Rect") {
343         $implIncludes{"DOMCSS.h"} = 1;
344         return;
345     }
346
347     # Temp DOMHTML.h
348     if ($type eq "HTMLDocument") {
349         $implIncludes{"DOMHTML.h"} = 1;
350         $implIncludes{"DOMHTMLInternal.h"} = 1;
351         $implIncludes{"$type.h"} = 1;
352         return;
353     }
354
355     # Temp DOMEvents.h
356     if ($type eq "Event") {
357         $implIncludes{"DOMEvents.h"} = 1;
358         $implIncludes{"DOMEventsInternal.h"} = 1;
359         $implIncludes{"$type.h"} = 1;
360         return;
361     }
362
363     # Temp DOMStyleSheets.h
364     if ($type eq "StyleSheetList") {
365         $implIncludes{"DOMStyleSheets.h"} = 1;
366         $implIncludes{"$type.h"} = 1;
367         return;
368     }
369     
370     # Temp DOMViews.h
371     if ($type eq "DOMWindow") {
372         $implIncludes{"DOMViews.h"} = 1;
373         $implIncludes{"DOMViewsInternal.h"} = 1;
374         $implIncludes{"$type.h"} = 1;
375         return;
376     }
377     
378     # Temp DOMXPath.h
379     if ($type eq "XPathExpression"
380             or $type eq "XPathNSResolver"
381             or $type eq "XPathResult") {
382         $implIncludes{"DOMXPath.h"} = 1;
383         $implIncludes{"DOMXPathInternal.h"} = 1;
384         $implIncludes{"$type.h"} = 1;
385         return;
386     }
387
388     # Temp DOMImplementationFront.h
389     if ($type eq "DOMImplementation") {
390         $implIncludes{"DOMImplementationFront.h"} = 1;
391     }
392
393     # Add type specific internal types.
394     $implIncludes{"DOMHTMLInternal.h"} = 1 if ($type =~ /^HTML/);
395
396     # Default, include the same named file (the implementation) and the same name prefixed with "DOM". 
397     $implIncludes{"$type.h"} = 1;
398     $implIncludes{"DOM$type.h"} = 1;
399 }
400
401 sub GenerateHeader
402 {
403     my $object = shift;
404     my $dataNode = shift;
405
406     # Make sure that we don't have more than one parent.
407     if (@{$dataNode->parents} > 1) {
408         die "A class can't have more than one parent.";
409     }
410
411     my $interfaceName = $dataNode->name;
412     my $className = GetClassName($interfaceName);
413     my $parentClassName = "DOM" . GetParentImplClassName($dataNode);
414
415     my $numConstants = @{$dataNode->constants};
416     my $numAttributes = @{$dataNode->attributes};
417     my $numFunctions = @{$dataNode->functions};
418
419     # - Add default header template
420     @headerContentHeader = split("\r", $headerLicenceTemplate);
421
422     # - INCLUDES -
423     push(@headerContentHeader, "\n#import <WebCore/$parentClassName.h> // parent class\n\n");
424
425     # - Add constants.
426     if ($numConstants > 0) {
427         my @headerConstants = ();
428         foreach my $constant (@{$dataNode->constants}) {
429
430             my $constantName = $constant->name;
431             my $constantValue = $constant->value;
432             my $output = "    DOM_" . $constantName . " = " . $constantValue;
433             
434             push(@headerConstants, $output);
435         }
436
437         my $combinedConstants = join(",\n", @headerConstants);
438
439         # FIXME: the formatting of the enums should line up the equal signs.
440         push(@headerContent, "\n// Constants\n");
441         push(@headerContent, "enum {\n");
442         push(@headerContent, $combinedConstants);
443         push(@headerContent, "\n};\n");        
444     }
445     
446     # - Begin @interface 
447     push(@headerContent, "\n\@interface $className : $parentClassName\n");
448
449     # - Add attribute getters/setters.
450     if ($numAttributes > 0) {
451         my @headerAttributes = ();
452
453         foreach (@{$dataNode->attributes}) {
454             my $attribute = $_;
455             
456             AddForwardDeclarationsForType($attribute->signature->type);
457
458             my $attributeName = $attribute->signature->name;
459             if ($attributeName eq "id") {
460                 # Special case attribute id to be idName to avoid Obj-C nameing conflict.
461                 $attributeName .= "Name";
462             } elsif ($attributeName eq "frame") {
463                 # Special case attribute frame to be frameBorders.
464                 $attributeName .= "Borders";
465             }
466
467             my $attributeType = GetObjCType($attribute->signature->type);
468             my $attributeIsReadonly = ($attribute->type =~ /^readonly/);
469
470             if ($ENV{"MACOSX_DEPLOYMENT_TARGET"} >= 10.5) {
471                 my $property = "\@property" . ($attributeIsReadonly ? "(readonly)" : "") . " " . $attributeType . ($attributeType =~ /\*$/ ? "" : " ") . $attributeName . ";\n";
472
473                 push(@headerAttributes, $property);
474             } else {
475                 # - GETTER
476                 my $getter = "- (" . $attributeType . ")" . $attributeName . ";\n";
477
478                 push(@headerAttributes, $getter);
479
480                 # - SETTER
481                 if (!$attributeIsReadonly) {
482                     my $setter = "- (void)set" . ucfirst($attributeName) . ":(" . $attributeType . ")new" . ucfirst($attributeName) . ";\n";
483                     
484                     push(@headerAttributes, $setter);
485                 }
486             }
487         }
488
489         if (@headerAttributes > 0) {
490             push(@headerContent, @headerAttributes);
491         }
492     }
493
494     # - Add functions.
495     if ($numFunctions > 0) {
496         my @headerFunctions = ();
497
498         foreach (@{$dataNode->functions}) {
499             my $function = $_;
500
501             AddForwardDeclarationsForType($function->signature->type);
502
503             my $functionName = $function->signature->name;
504             my $returnType = GetObjCType($function->signature->type);
505             my $numberOfParameters = @{$function->parameters};
506
507             my $output = "- ($returnType)$functionName";
508             foreach my $param (@{$function->parameters}) {
509                 my $paramName = $param->name;
510                 my $paramType = GetObjCType($param->type);
511                 AddForwardDeclarationsForType($param->type);
512
513                 $output .= ":($paramType)$paramName ";
514             }
515             # remove any trailing spaces.
516             $output =~ s/\s+$//;
517             $output .= ";\n";
518     
519             push(@headerFunctions, $output);
520         }
521
522         if (@headerFunctions > 0) {
523             push(@headerContent, "\n");
524             push(@headerContent, @headerFunctions);
525         }
526     }
527
528     # - End @interface 
529     push(@headerContent, "\@end\n");
530 }
531
532 sub GenerateImplementation
533 {
534     my $object = shift;
535     my $dataNode = shift;
536
537     my $interfaceName = $dataNode->name;
538     my $className = GetClassName($interfaceName);
539     my $implClassName = GetImplClassName($interfaceName);
540     my $parentImplClassName = GetParentImplClassName($dataNode);
541
542     my $numAttributes = @{$dataNode->attributes};
543     my $numFunctions = @{$dataNode->functions};
544     my $hasFunctionsOrAttributes = $numAttributes + $numFunctions;
545
546     # - Add default header template.
547     @implContentHeader = split("\r", $implementationLicenceTemplate);
548
549     # - INCLUDES -
550     push(@implContentHeader, "\n#import \"config.h\"\n");
551     push(@implContentHeader, "#import \"$className.h\"\n\n");
552
553     if ($hasFunctionsOrAttributes) {
554         push(@implContentHeader, "#import \"DOMInternal.h\"\n");
555         push(@implContentHeader, "#import <wtf/GetPtr.h>\n");
556         
557         # include module-dependent internal interfaces.
558         if ($module eq "html") {
559             # HTML module internal interfaces
560             push(@implContentHeader, "#import \"DOMHTMLInternal.h\"\n");
561         } elsif ($module eq "css") {
562             # CSS module internal interfaces
563             push(@implContentHeader, "#import \"DOMCSSInternal.h\"\n");
564         } elsif ($module eq "events") {
565             # CSS module internal interfaces
566             push(@implContentHeader, "#import \"DOMEventsInternal.h\"\n");
567         } elsif ($module eq "xpath") {
568             # CSS module internal interfaces
569             push(@implContentHeader, "#import \"DOMXPathInternal.h\"\n");
570         }
571
572         # include Implementation class
573         push(@implContentHeader, "#import \"$interfaceName.h\" // implementation class\n");
574         if ($interfaceName eq "DOMImplementation") {
575             # FIXME: needed until we can remove DOMImplementationFront
576             push(@implContentHeader, "#import \"DOMImplementationFront.h\"\n");
577         }
578     }
579
580     @implContent = ();
581
582     # START implementation
583     push(@implContent, "\n\@implementation $className\n\n");
584
585     if ($hasFunctionsOrAttributes) {
586         if ($parentImplClassName eq "Object") {
587             # Only generate 'dealloc' and 'finalize' methods for direct subclasses of DOMObject.
588
589             push(@implContent, "#define IMPL reinterpret_cast<$implClassName*>(_internal)\n\n");
590
591             push(@implContent, "- (void)dealloc\n");
592             push(@implContent, "{\n");
593             push(@implContent, "    if (_internal)\n");
594             push(@implContent, "        IMPL->deref();\n");
595             push(@implContent, "    [super dealloc];\n");
596             push(@implContent, "}\n\n");
597
598             push(@implContent, "- (void)finalize\n");
599             push(@implContent, "{\n");
600             push(@implContent, "    if (_internal)\n");
601             push(@implContent, "        IMPL->deref();\n");
602             push(@implContent, "    [super finalize];\n");
603             push(@implContent, "}\n\n");
604         } else {
605             my $internalBaseType;
606             if ($interfaceName =~ /^CSS.+Value$/) {
607                 $internalBaseType = "WebCore::CSSValue"
608             } elsif ($interfaceName =~ /^CSS.+Rule$/) {
609                 $internalBaseType = "WebCore::CSSRule"
610             } else {
611                 $internalBaseType = "WebCore::Node"
612             }
613
614             push(@implContent, "#define IMPL static_cast<$implClassName*>(reinterpret_cast<$internalBaseType*>(_internal))\n\n");
615         }
616     }
617
618     # - Attributes
619     if ($numAttributes > 0) {
620         foreach (@{$dataNode->attributes}) {
621             my $attribute = $_;
622
623             AddIncludesForType($attribute->signature->type);
624
625             my $attributeName = $attribute->signature->name;
626             my $attributeType = GetObjCType($attribute->signature->type);
627             my $attributeIsReadonly = ($attribute->type =~ /^readonly/);
628
629             my $interfaceName = $attributeName;
630             if ($attributeName eq "id") {
631                 # Special case attribute id to be idName to avoid Obj-C nameing conflict.
632                 $interfaceName .= "Name";
633             } elsif ($attributeName eq "frame") {
634                 # Special case attribute frame to be frameBorders.
635                 $interfaceName .= "Borders";
636             }
637
638             # - GETTER
639             my $getterSig = "- ($attributeType)$interfaceName\n";
640             
641             # Exception handling
642             my $hasGetterException = @{$attribute->getterExceptions};
643             if ($hasGetterException) {
644                 die "We should not have any getter exceptions yet!";
645             }
646             
647             my $getterContentHead = "IMPL->$attributeName(";
648             my $getterContentTail = ")";
649
650             my $attributeTypeSansPtr = $attributeType;
651             $attributeTypeSansPtr =~ s/ \*$//; # Remove trailing " *" from pointer types.
652             my $typeMaker = GetObjCTypeMaker($attribute->signature->type);
653             
654             # Special cases
655             if ($attributeTypeSansPtr eq "DOMImplementation") {
656                 # FIXME: We have to special case DOMImplementation until DOMImplementationFront is removed
657                 $getterContentHead = "[$attributeTypeSansPtr $typeMaker:implementationFront(IMPL";
658                 $getterContentTail .= "]";
659             } elsif ($attributeName =~ /(\w+)DisplayString$/) {
660                 my $attributeToDisplay = $1;
661                 $getterContentHead = "IMPL->$attributeToDisplay().replace(\'\\\\\', [self _element]->document()->backslashAsCurrencySymbol()";
662                 $implIncludes{"Document.h"} = 1;
663             } elsif ($typeMaker ne "") {
664                 # Surround getter with TypeMaker
665                 $getterContentHead = "[$attributeTypeSansPtr $typeMaker:WTF::getPtr(" . $getterContentHead;
666                 $getterContentTail .= ")]";
667             }
668             
669             my $getterContent;
670             if ($hasGetterException) {
671                 $getterContent = $getterContentHead . "ec" . $getterContentTail;
672             } else {
673                 $getterContent = $getterContentHead . $getterContentTail;
674             }
675             
676             push(@implContent, $getterSig);
677             push(@implContent, "{\n");
678             if ($hasGetterException) {
679                 # Differentiated between when the return type is a pointer and
680                 # not for white space issue (ie. Foo *result vs. int result).
681                 if ($attributeType =~ /\*$/) {
682                     $getterContent = $attributeType . "result = " . $getterContent;
683                 } else {
684                     $getterContent = $attributeType . " result = " . $getterContent;
685                 }
686
687                 push(@implContent, "    $exceptionInit\n");
688                 push(@implContent, "    $getterContent;\n");
689                 push(@implContent, "    $exceptionRaiseOnError\n");
690                 push(@implContent, "    return result;\n");
691             } else {
692                 push(@implContent, "    return $getterContent;\n");
693             }
694             push(@implContent, "}\n\n");
695
696             # - SETTER
697             if (!$attributeIsReadonly) {
698                 # Exception handling
699                 my $hasSetterException = @{$attribute->setterExceptions};
700
701                 $attributeName = "set" . ucfirst($attributeName);
702                 my $setterName = "set" . ucfirst($interfaceName);
703                 my $argName = "new" . ucfirst($interfaceName);
704
705                 my $setterSig = "- (void)$setterName:($attributeType)$argName\n";
706
707                 push(@implContent, $setterSig);
708                 push(@implContent, "{\n");
709
710                 if ($hasSetterException) {
711                     # FIXME: asserts exsist in the exsisting bindings, but I am unsure why they are 
712                     # there in the first place;
713                     push(@implContent, "    ASSERT($argName);\n\n");
714
715                     push(@implContent, "    $exceptionInit\n");
716                     push(@implContent, "    IMPL->$attributeName($argName, ec);\n");
717                     push(@implContent, "    $exceptionRaiseOnError\n");
718                 } else {
719                     push(@implContent, "    IMPL->$attributeName($argName);\n");
720                 }
721
722                 push(@implContent, "}\n\n");
723             }
724         }
725     }
726
727     # - Functions
728     if ($numFunctions > 0) {
729         foreach (@{$dataNode->functions}) {
730             my $function = $_;
731
732             AddIncludesForType($function->signature->type);
733
734             my $functionName = $function->signature->name;
735             my $returnType = GetObjCType($function->signature->type);
736             my $hasParameters = @{$function->parameters};
737             my $raisesExceptions = @{$function->raisesExceptions};
738
739             my @parameterNames = ();
740             my @needsAssert = ();
741             my %custom = ();
742
743             my $functionSig = "- ($returnType)$functionName";
744             foreach (@{$function->parameters}) {
745                 my $param = $_;
746
747                 my $paramType = GetObjCType($param->type);
748                 AddIncludesForType($param->type);
749
750                 my $paramName = $param->name;
751
752                 # FIXME: should move this out into it's own fuction to take care of possible special cases.
753                 my $idlType = $codeGenerator->StripModule($param->type);
754                 if ($codeGenerator->IsPrimitiveType($idlType) or $idlType eq "DOMString") {
755                     push(@parameterNames, $paramName);
756                 } elsif ($idlType eq "XPathNSResolver") {
757                     my $implGetter = "[nativeResolver _xpathNSResolver]";
758                     push(@parameterNames, $implGetter);
759                     $needsCustom{"XPathNSResolver"} = $paramName;
760                 } elsif ($idlType eq "XPathResult") {
761                     my $implGetter = "[" . $paramName . " _xpathResult]";
762                     push(@parameterNames, $implGetter);
763                 } else {
764                     my $implGetter = "[" . $paramName . " _" . lcfirst($idlType) . "]";
765                     push(@parameterNames, $implGetter);
766                 }
767
768                 if (!$param->extendedAttributes->{"IsIndex"}) {
769                     push(@needsAssert, "    ASSERT($paramName);\n");
770                 }
771
772                 $functionSig .= ":($paramType)$paramName ";
773             }
774             # remove any trailing spaces.
775             $functionSig =~ s/\s+$//;
776
777             my @functionContent = ();
778
779             if ($returnType eq "void") {
780                 # Special case 'void' return type.
781                 my $functionContentHead = "IMPL->$functionName(";
782                 my $functionContentTail = ");";
783                 my $content = "";
784
785                 if ($hasParameters) {
786                     my $params = join(", ", @parameterNames);
787                     if ($raisesExceptions) {
788                         $content = $functionContentHead . $params . ", ec" . $functionContentTail;
789                     } else {
790                         $content = $functionContentHead . $params . $functionContentTail;
791                     }
792                 } else {
793                     if ($raisesExceptions) {
794                         $content = $functionContentHead . "ec" . $functionContentTail;
795                     } else {
796                         $content = $functionContentHead . $functionContentTail;
797                     }
798                 }
799                 
800                 if ($raisesExceptions) {
801                     push(@functionContent, "    $exceptionInit\n");
802                     push(@functionContent, "    $content\n");
803                     push(@functionContent, "    $exceptionRaiseOnError\n");
804                 } else {
805                     push(@functionContent, "    $content\n");
806                 }
807             } else {
808                 my $functionContentHead = "IMPL->" . $functionName . "(";
809                 my $functionContentTail = ")";
810
811                 my $typeMaker = GetObjCTypeMaker($function->signature->type);
812                 unless ($typeMaker eq "") {
813                     my $returnTypeClass = "";
814                     if ($function->signature->type eq "XPathNSResolver") {
815                         # Special case XPathNSResolver
816                         $returnTypeClass = "DOMNativeXPathNSResolver";
817                     } else {
818                         # Remove trailing " *" from pointer types.
819                         $returnTypeClass = $returnType;
820                         $returnTypeClass =~ s/ \*$//;
821                     }
822
823                     # Surround getter with TypeMaker
824                     $functionContentHead = "[$returnTypeClass $typeMaker:WTF::getPtr(" . $functionContentHead;
825                     $functionContentTail .= ")]";
826                 }
827
828                 my $content = "";
829
830                 if ($hasParameters) {
831                     my $params = join(", " , @parameterNames);
832                     if ($raisesExceptions) {
833                         # A temparary variable is needed.
834                         $content = $functionContentHead . $params . ", ec" . $functionContentTail;
835                     } else {
836                         $content = $functionContentHead . $params . $functionContentTail;
837                     }
838                 } else {
839                     if ($raisesExceptions) {
840                         # A temparary variable is needed.
841                         $content = $functionContentHead . "ec" . $functionContentTail;
842                     } else {
843                         $content = $functionContentHead . $functionContentTail;
844                     }
845                 }
846                 
847                 if ($raisesExceptions) {
848                     # Differentiated between when the return type is a pointer and
849                     # not for white space issue (ie. Foo *result vs. int result).
850                     if ($returnType =~ /\*$/) {
851                         $content = $returnType . "result = " . $content;
852                     } else {
853                         $content = $returnType . " result = " . $content;
854                     }
855                     
856                     push(@functionContent, "    $exceptionInit\n");
857                     push(@functionContent, "    $content;\n");
858                     push(@functionContent, "    $exceptionRaiseOnError\n");
859                     push(@functionContent, "    return result;\n");
860                 } else {
861                     push(@functionContent, "    return $content;\n");
862                 }
863             }
864
865             push(@implContent, "$functionSig\n");
866             push(@implContent, "{\n");
867             
868             # special case the XPathNSResolver
869             if (defined $needsCustom{"XPathNSResolver"}) {
870                 my $paramName = $needsCustom{"XPathNSResolver"};
871                 push(@implContent, "    if ($paramName && ![$paramName isMemberOfClass:[DOMNativeXPathNSResolver class]])\n");
872                 push(@implContent, "        [NSException raise:NSGenericException format:\@\"createExpression currently does not work with custom NS resolvers\"];\n");
873                 push(@implContent, "    DOMNativeXPathNSResolver *nativeResolver = (DOMNativeXPathNSResolver *)$paramName;\n\n");
874             }
875
876             push(@implContent, @functionContent);
877             push(@implContent, "}\n\n");
878             
879             # Clear the hash
880             %needsCustom = ();
881         }
882     }
883
884     # END implementation
885     push(@implContent, "\@end\n");
886 }
887
888 # Internal helper
889 sub WriteData
890 {
891     if (defined($IMPL)) {
892         # Write content to file.
893         print $IMPL @implContentHeader;
894         
895         foreach my $implInclude (sort keys(%implIncludes)) {
896             print $IMPL "#import \"$implInclude\"\n";
897         }
898         
899         print $IMPL @implContent;
900         close($IMPL);
901         undef($IMPL);
902         
903         @implHeaderContent = "";
904         @implContent = "";    
905         %implIncludes = ();
906     }
907
908     if (defined($HEADER)) {
909         # Write content to file.
910         print $HEADER @headerContentHeader;
911         
912         foreach my $forwardClassDeclaration (sort keys(%headerForwardDeclarations)) {
913             print $HEADER "\@class $forwardClassDeclaration;\n";
914         }
915         
916         foreach my $forwardProtocolDeclaration (sort keys(%headerForwardDeclarationsForProtocols)) {
917             print $HEADER "\@protocol $forwardProtocolDeclaration;\n";
918         }
919
920         print $HEADER @headerContent;
921         close($HEADER);
922         undef($HEADER);
923         
924         @headerContentHeader = "";
925         @headerContent = "";
926         %headerForwardDeclarations = ();
927     }
928 }
929
930 1;