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