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