2006-10-02 Nikolas Zimmermann <zimmermann@kde.org>
[WebKit-https.git] / WebCore / bindings / scripts / CodeGeneratorJS.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 CodeGeneratorJS;
28
29 use File::stat;
30
31 my $module = "";
32 my $outputDir = "";
33 my %implIncludes = ();
34
35 # Default .h template
36 my $headerTemplate = << "EOF";
37 /*
38     This file is part of the WebKit open source project.
39     This file has been generated by generate-bindings.pl. DO NOT MODIFY!
40
41     This library is free software; you can redistribute it and/or
42     modify it under the terms of the GNU Library General Public
43     License as published by the Free Software Foundation; either
44     version 2 of the License, or (at your option) any later version.
45
46     This library is distributed in the hope that it will be useful,
47     but WITHOUT ANY WARRANTY; without even the implied warranty of
48     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
49     Library General Public License for more details.
50
51     You should have received a copy of the GNU Library General Public License
52     along with this library; see the file COPYING.LIB.  If not, write to
53     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
54     Boston, MA 02111-1307, USA.
55 */
56 EOF
57
58 # Default constructor
59 sub new
60 {
61     my $object = shift;
62     my $reference = { };
63
64     $codeGenerator = shift;
65     $outputDir = shift;
66
67     bless($reference, $object);
68     return $reference;
69 }
70
71 sub finish
72 {
73     my $object = shift;
74
75     # Commit changes!
76     $object->WriteData();
77 }
78
79 sub leftShift($$) {
80     my ($value, $distance) = @_;
81     return (($value << $distance) & 0xFFFFFFFF);
82 }
83
84 # Params: 'domClass' struct
85 sub GenerateInterface
86 {
87     my $object = shift;
88     my $dataNode = shift;
89     my $defines = shift;
90
91     # Start actual generation
92     $object->GenerateHeader($dataNode);
93     $object->GenerateImplementation($dataNode);
94
95     my $name = $dataNode->name;
96
97     # Open files for writing
98     my $headerFileName = "$outputDir/JS$name.h";
99     my $implFileName = "$outputDir/JS$name.cpp";
100     
101     open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
102     open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
103 }
104
105 # Params: 'idlDocument' struct
106 sub GenerateModule
107 {
108     my $object = shift;
109     my $dataNode = shift;  
110     
111     $module = $dataNode->module;    
112 }
113
114 sub GetParentClassName
115 {
116     my $dataNode = shift;
117     return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"};
118     return "KJS::DOMObject" if @{$dataNode->parents} eq 0;
119     return "JS" . $codeGenerator->StripModule($dataNode->parents(0));
120 }
121
122 sub GetLegacyHeaderIncludes
123 {
124     my $legacyParent = shift;
125     if ($legacyParent eq "JSHTMLInputElementBase") {
126         return "#include \"JSHTMLInputElementBase.h\"\n\n";
127     } elsif ($legacyParent eq "KJS::Window") {
128         return "#include \"kjs_window.h\"\n\n";
129     } elsif ($legacyParent eq "KJS::DOMNode") {
130         return "#include \"kjs_domnode.h\"\n\n";
131     } elsif ($module eq "events") {
132         return "#include \"kjs_events.h\"\n\n";
133     } elsif ($module eq "core") {
134         return "#include \"kjs_dom.h\"\n\n";
135     } elsif ($module eq "css") {
136         return "#include \"kjs_css.h\"\n\n";
137     } elsif ($module eq "html") {
138         return "#include \"kjs_html.h\"\n\n";
139     } elsif ($module eq "traversal") {
140         return "#include \"kjs_traversal.h\"\n\n";
141     } else {
142         die ("Don't know what headers to include for module $module");
143     }
144 }
145
146 sub AvoidInclusionOfType
147 {
148     my $type = shift;
149
150     # Special case: SVGRect.h / SVGPoint.h / SVGNumber.h do not exist.
151     if ($type eq "SVGRect" or
152         $type eq "SVGPoint" or
153         $type eq "SVGNumber") {
154         return 1;
155     }
156
157     return 0;
158 }
159  
160 sub AddIncludesForType
161 {
162     my $type = $codeGenerator->StripModule(shift);
163     
164     # When we're finished with the one-file-per-class 
165     # reorganization, we won't need these special cases.
166     if ($codeGenerator->IsPrimitiveType($type)
167         or $type eq "DOMString" or $type eq "DOMObject" or $type eq "RGBColor" or $type eq "Rect") {
168     } elsif ($type =~ /SVGPathSeg/) {
169         $joinedName = $type;
170         $joinedName =~ s/Abs|Rel//;
171         $implIncludes{"${joinedName}.h"} = 1;
172     } else {
173         # default, include the same named file
174         $implIncludes{"${type}.h"} = 1 unless(AvoidInclusionOfType($type));
175     }
176
177     # additional includes (things needed to compile the bindings but not the header)
178
179     if ($type eq "CanvasRenderingContext2D") {
180         $implIncludes{"CanvasGradient.h"} = 1;
181         $implIncludes{"CanvasPattern.h"} = 1;
182         $implIncludes{"CanvasStyle.h"} = 1;
183     }
184
185     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
186         $implIncludes{"PlatformString.h"} = 1;
187     }
188 }
189
190 sub AddIncludesForSVGAnimatedType
191 {
192     my $type = shift;
193     $type =~ s/SVGAnimated//; 
194
195     if ($type eq "SVGRect" or
196         $type eq "SVGPoint" or
197         $type eq "SVGNumber") {
198       $implIncludes{"JSSVG$type.h"} = 1;
199     } else {
200       push(@implContentHeader, "#include \"PlatformString.h\"\n") if($type eq "String");
201     }
202 }
203
204 sub AddClassForwardIfNeeded
205 {
206     my $implClassName = shift;
207
208     # SVGAnimatedLength/Number/etc.. are typedefs to SVGAnimtatedTemplate, so don't use class forwards for them!
209     push(@headerContent, "class $implClassName;\n\n") unless($codeGenerator->IsSVGAnimatedType($implClassName));
210 }
211
212 sub GenerateHeader
213 {
214     my $object = shift;
215     my $dataNode = shift;
216
217     my $interfaceName = $dataNode->name;
218     my $className = "JS$interfaceName";
219     my $implClassName = $interfaceName;
220
221     # We only support multiple parents with SVG (for now).
222     if (@{$dataNode->parents} > 1) {
223         die "A class can't have more than one parent" unless $interfaceName =~ /SVG/;
224         $codeGenerator->AddMethodsConstantsAndAttributesFromParentClasses($dataNode);
225     }
226     
227     my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
228     my $hasRealParent = @{$dataNode->parents} > 0;
229     my $hasParent = $hasLegacyParent || $hasRealParent;
230     my $parentClassName = GetParentClassName($dataNode);
231     my $conditional = $dataNode->extendedAttributes->{"Conditional"};
232     
233     # - Add default header template
234     @headerContent = split("\r", $headerTemplate);
235     
236     # - Add header protection
237     push(@headerContent, "\n#ifndef $className" . "_H");
238     push(@headerContent, "\n#define $className" . "_H\n\n");
239     
240     push(@headerContent, "#ifdef ${conditional}_SUPPORT\n\n") if $conditional;
241     
242     if (exists $dataNode->extendedAttributes->{"LegacyParent"}) {
243         push(@headerContent, GetLegacyHeaderIncludes($dataNode->extendedAttributes->{"LegacyParent"}));
244     } else {
245         if ($hasParent) {
246             push(@headerContent, "#include \"$parentClassName.h\"\n");
247         } else {
248             push(@headerContent, "#include \"kjs_binding.h\"\n");
249         }
250     }
251
252     my $numConstants = @{$dataNode->constants};
253     my $numAttributes = @{$dataNode->attributes};
254     my $numFunctions = @{$dataNode->functions};
255
256     push(@headerContent, "\nnamespace WebCore {\n\n");
257     
258     # Implementation class forward declaration
259     AddClassForwardIfNeeded($implClassName);
260
261     # Class declaration
262     push(@headerContent, "class $className : public $parentClassName {\n");
263     push(@headerContent, "public:\n");
264     
265     # Constructor
266     if ($dataNode->extendedAttributes->{"DoNotCache"}) {
267         push(@headerContent, "    $className($implClassName*);\n");
268     } else {
269         push(@headerContent, "    $className(KJS::ExecState*, $implClassName*);\n");
270     }
271     
272     # Destructor
273     if (!$hasParent or $interfaceName eq "Document") {
274         push(@headerContent, "    virtual ~$className();\n");
275     }
276   
277     # Getters
278     if ($numAttributes > 0) {
279         push(@headerContent, "    virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
280         push(@headerContent, "    KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
281     }
282     
283     # Check if we have any writable properties
284     my $hasReadWriteProperties = 0;
285     foreach(@{$dataNode->attributes}) {
286         if($_->type !~ /^readonly\ attribute$/) {
287             $hasReadWriteProperties = 1;
288         }
289     }
290     
291     if ($hasReadWriteProperties) {
292         push(@headerContent, "    virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);\n");
293         push(@headerContent, "    void putValueProperty(KJS::ExecState*, int, KJS::JSValue*, int attr);\n");
294     }
295     
296     # Class info
297     push(@headerContent, "    virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
298     push(@headerContent, "    static const KJS::ClassInfo info;\n");
299
300     # Custom mark function
301     if ($dataNode->extendedAttributes->{"CustomMarkFunction"}) {
302         push(@headerContent, "\n    virtual void mark();\n\n");
303     }
304
305     # Constructor object getter
306     if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
307         push(@headerContent, "    static KJS::JSValue* getConstructor(KJS::ExecState*);\n")
308     }
309     
310     my $numCustomFunctions = 0;
311     my $numCustomAttributes = 0;
312     
313     # Attribute and function enums
314     if ($numAttributes + $numFunctions > 0) {
315         push(@headerContent, "    enum {\n")
316     }
317   
318     if ($numAttributes > 0) {
319         push(@headerContent, "        // Attributes\n        ");
320         
321         my $i = -1;
322         foreach(@{$dataNode->attributes}) {
323             my $attribute = $_;
324             
325             $numCustomAttributes++ if $attribute->signature->extendedAttributes->{"Custom"};
326             
327             $i++;
328             if((($i % 4) eq 0) and ($i ne 0)) {
329                 push(@headerContent, "\n        ");
330             }
331             
332             my $value = $attribute->signature->type =~ /Constructor$/
333                       ? $attribute->signature->name . "ConstructorAttrNum" 
334                       : ucfirst($attribute->signature->name) . "AttrNum";
335             $value .= ", " if(($i < $numAttributes - 1));
336             $value .= ", " if(($i eq $numAttributes - 1) and ($numFunctions ne 0));
337             push(@headerContent, $value);
338         }
339     }
340     
341     if ($numFunctions > 0) {
342         if ($numAttributes > 0) {
343             push(@headerContent, "\n\n");
344         }
345         push(@headerContent,"        // Functions\n        ");
346         
347         $i = -1;
348         foreach(@{$dataNode->functions}) {
349             my $function = $_;
350             
351             $i++;
352             if ((($i % 4) eq 0) and ($i ne 0)) {
353                 push(@headerContent, "\n        ");
354             }
355             
356             $numCustomFunctions++ if $function->signature->extendedAttributes->{"Custom"};
357             
358             my $value = ucfirst($function->signature->name) . "FuncNum";
359             $value .= ", " if ($i < $numFunctions - 1);
360             push(@headerContent, $value);
361         }
362     }
363   
364     if ($numAttributes + $numFunctions > 0) {
365         push(@headerContent, "\n    };\n");
366     }
367
368     if ($numCustomAttributes > 0) {
369         push(@headerContent, "\n    // Custom attributes\n");
370         
371         foreach(@{$dataNode->attributes}) {
372             my $attribute = $_;
373               
374             if ($attribute->signature->extendedAttributes->{"Custom"}) {
375                 push(@headerContent, "    KJS::JSValue* " . $attribute->signature->name . "(KJS::ExecState*) const;\n");
376                 if ($attribute->type !~ /^readonly/) {
377                     push(@headerContent, "    void set" . ucfirst($attribute->signature->name) . "(KJS::ExecState*, KJS::JSValue*);\n");        
378                 }
379             }
380         }
381     }
382   
383     if ($numCustomFunctions > 0) {      
384         push(@headerContent, "\n    // Custom functions\n");
385         foreach(@{$dataNode->functions}) {
386             my $function = $_;
387               
388             if ($function->signature->extendedAttributes->{"Custom"}) {
389                 push(@headerContent, "    KJS::JSValue* " . $function->signature->name . "(KJS::ExecState*, const KJS::List&);\n");
390             }
391         }
392     }
393
394     # Index setter
395     if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
396         push(@headerContent, "    void indexSetter(KJS::ExecState*, const KJS::Identifier &propertyName, KJS::JSValue*, int attr);\n");
397     }
398
399     if (!$hasParent) {
400         push(@headerContent, "    $implClassName* impl() const { return m_impl.get(); }\n");
401         push(@headerContent, "private:\n");
402         push(@headerContent, "    RefPtr<$implClassName> m_impl;\n");
403     } elsif ($dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
404         push(@headerContent, "    $implClassName* impl() const;\n");
405     }
406   
407     # Index getter
408     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
409         push(@headerContent, "private:\n");
410         push(@headerContent, "    static KJS::JSValue* indexGetter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);\n");
411     }
412     # Name getter
413     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
414         push(@headerContent, "private:\n");
415         push(@headerContent, "    static KJS::JSValue* nameGetter(KJS::ExecState*, KJS::JSObject*, const KJS::Identifier&, const KJS::PropertySlot&);\n");
416         push(@headerContent, "    static bool canGetItemsForName(KJS::ExecState*, $implClassName*, const AtomicString&);\n")
417     }
418   
419     push(@headerContent, "};\n\n");
420     
421     if (!$hasParent) {
422         push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, $implClassName*);\n");
423     }
424     if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
425         push(@headerContent, "$implClassName* to${interfaceName}(KJS::JSValue*);\n");
426     }
427     push(@headerContent, "\n");
428     
429     # Add prototype declaration -- code adopted from the KJS_DEFINE_PROTOTYPE and KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE macros
430     push(@headerContent, "class ${className}Proto : public KJS::JSObject {\n");
431     push(@headerContent, "public:\n");
432     if ($dataNode->extendedAttributes->{"DoNotCache"}) {
433         push(@headerContent, "    static KJS::JSObject* self();\n");
434     } else {
435         push(@headerContent, "    static KJS::JSObject* self(KJS::ExecState* exec);\n");
436     }
437     push(@headerContent, "    virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
438     push(@headerContent, "    static const KJS::ClassInfo info;\n");
439     if ($numFunctions > 0 || $numConstants > 0) {
440         push(@headerContent, "    bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
441     }
442     if ($numConstants ne 0) {
443         push(@headerContent, "    KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
444     }
445     if ($dataNode->extendedAttributes->{"DoNotCache"}) {
446         push(@headerContent, "    ${className}Proto() { }\n");
447     } else {
448         push(@headerContent, "    ${className}Proto(KJS::ExecState* exec)\n");
449         if ($hasParent && $parentClassName ne "KJS::DOMCSSRule" && $parentClassName ne "KJS::DOMNodeFilter") {
450             push(@headerContent, "        : KJS::JSObject(${parentClassName}Proto::self(exec)) { }\n");
451         } else {
452             push(@headerContent, "        : KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { }\n");
453         }
454     }
455     
456     push(@headerContent, "};\n\n");
457     
458     push(@headerContent, "}\n\n");
459     
460     push(@headerContent, "#endif // ${conditional}_SUPPORT\n\n") if $conditional;
461     
462     push(@headerContent, "#endif\n");
463 }
464
465 sub GenerateImplementation
466 {
467   my $object = shift;
468   my $dataNode = shift;
469
470   my $interfaceName = $dataNode->name;
471   my $className = "JS$interfaceName";
472   my $implClassName = $interfaceName;
473   
474   my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
475   my $hasRealParent = @{$dataNode->parents} > 0;
476   my $hasParent = $hasLegacyParent || $hasRealParent;
477   my $parentClassName = GetParentClassName($dataNode);
478   my $conditional = $dataNode->extendedAttributes->{"Conditional"};
479   
480   # - Add default header template
481   @implContentHeader = split("\r", $headerTemplate);
482   push(@implContentHeader, "\n");
483   push(@implContentHeader,, "#include \"config.h\"\n\n");
484   
485   push(@implContentHeader, "#ifdef ${conditional}_SUPPORT\n\n") if $conditional;
486
487   if ($className =~ /^JSSVGAnimated/) {
488     AddIncludesForSVGAnimatedType($interfaceName);
489   }
490   
491   push(@implContentHeader, "#include \"SVGAnimatedTemplate.h\"\n") if($className =~ /SVG/);
492   push(@implContentHeader, "#include \"$className.h\"\n\n");
493  
494   AddIncludesForType($interfaceName);
495
496   @implContent = ();
497
498   push(@implContent, "\nusing namespace KJS;\n\n");  
499   push(@implContent, "namespace WebCore {\n\n");
500   
501   # - Add all attributes in a hashtable definition
502   my $numAttributes = @{$dataNode->attributes};
503   if ($numAttributes > 0) {
504     my $hashSize = $numAttributes;
505     my $hashName = $className . "Table";
506
507     my @hashKeys = ();      # ie. 'insertBefore'
508     my @hashValues = ();    # ie. 'JSNode::InsertBefore'
509     my @hashSpecials = ();    # ie. 'DontDelete|Function'
510     my @hashParameters = ();  # ie. '2'
511
512     foreach my $attribute (@{$dataNode->attributes}) {
513       my $name = $attribute->signature->name;
514       push(@hashKeys, $name);
515       
516       my $value = $className . "::" . ($attribute->signature->type =~ /Constructor$/ 
517                                        ? $attribute->signature->name . "ConstructorAttrNum" 
518                                        : ucfirst($attribute->signature->name) . "AttrNum");      
519       push(@hashValues, $value);
520
521       my $special = "DontDelete";
522       $special .= "|ReadOnly" if($attribute->type =~ /readonly/);
523       push(@hashSpecials, $special);
524
525       my $numParameters = "0";
526       push(@hashParameters, $numParameters);      
527     }
528
529     $object->GenerateHashTable($hashName, $hashSize,
530                                \@hashKeys, \@hashValues,
531                                \@hashSpecials, \@hashParameters);
532   }
533   
534   my $numConstants = @{$dataNode->constants};
535   my $numFunctions = @{$dataNode->functions};
536
537   # - Add all constants
538   if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
539     $hashSize = $numConstants;
540     $hashName = $className . "ConstructorTable";
541
542     @hashKeys = ();
543     @hashValues = ();
544     @hashSpecials = ();
545     @hashParameters = ();
546
547     foreach my $constant (@{$dataNode->constants}) {
548       my $name = $constant->name;
549       push(@hashKeys, $name);
550       
551       my $value = "${implClassName}::$name";
552       push(@hashValues, $value);
553       
554       my $special = "DontDelete|ReadOnly";
555       push(@hashSpecials, $special);
556       
557       my $numParameters = 0;
558       push(@hashParameters, $numParameters); 
559     }
560
561     $object->GenerateHashTable($hashName, $hashSize,
562                                \@hashKeys, \@hashValues,
563                                \@hashSpecials, \@hashParameters);
564
565     my $protoClassName;
566     $protoClassName = "${className}Proto";
567
568     push(@implContent, constructorFor($className, $protoClassName, $interfaceName, $dataNode->extendedAttributes->{"CanBeConstructed"}));
569   }
570   
571   # - Add functions and constants to a hashtable definition
572   $hashSize = $numFunctions + $numConstants;
573   $hashName = $className . "ProtoTable";
574
575   @hashKeys = ();
576   @hashValues = ();
577   @hashSpecials = ();
578   @hashParameters = ();
579
580   foreach my $constant (@{$dataNode->constants}) {
581       my $name = $constant->name;
582       push(@hashKeys, $name);
583         
584       my $value = "${implClassName}::$name";
585       push(@hashValues, $value);
586         
587       my $special = "DontDelete|ReadOnly";
588       push(@hashSpecials, $special);
589         
590       my $numParameters = 0;
591       push(@hashParameters, $numParameters); 
592   }
593     
594   foreach my $function (@{$dataNode->functions}) {
595     my $name = $function->signature->name;
596     push(@hashKeys, $name);
597     
598     my $value = $className . "::" . ucfirst($name) . "FuncNum";
599     push(@hashValues, $value);
600     
601     my $special = "DontDelete|Function";
602     push(@hashSpecials, $special);
603     
604     my $numParameters = @{$function->parameters};
605     push(@hashParameters, $numParameters);
606   }
607     
608   $object->GenerateHashTable($hashName, $hashSize,
609                              \@hashKeys, \@hashValues,
610                              \@hashSpecials, \@hashParameters);
611
612   if($numFunctions > 0) {
613       push(@implContent, protoFuncFor($className));
614   }
615
616   push(@implContent, "const ClassInfo ${className}Proto::info = { \"$interfaceName\", 0, &${className}ProtoTable, 0 };\n\n");
617   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
618       push(@implContent, "JSObject* ${className}Proto::self()\n");
619       push(@implContent, "{\n");
620       push(@implContent, "    return new ${className}Proto();\n");
621       push(@implContent, "}\n\n");
622   } else {
623       push(@implContent, "JSObject* ${className}Proto::self(ExecState* exec)\n");
624       push(@implContent, "{\n");
625       push(@implContent, "    return KJS::cacheGlobalObject<${className}Proto>(exec, \"[[${className}.prototype]]\");\n");
626       push(@implContent, "}\n\n");
627   }
628   if ($numConstants > 0 || $numFunctions > 0) {
629       push(@implContent, "bool ${className}Proto::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
630       push(@implContent, "{\n");
631       if ($numConstants eq 0) {
632           push(@implContent, "    return getStaticFunctionSlot<${className}ProtoFunc, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
633       } elsif ($numFunctions eq 0) {
634           push(@implContent, "    return getStaticValueSlot<${className}Proto, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
635       } else {
636           push(@implContent, "    return getStaticPropertySlot<${className}ProtoFunc, ${className}Proto, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
637       }
638       push(@implContent, "}\n\n");
639   }
640   if ($numConstants ne 0) {
641       push(@implContent, "JSValue* ${className}Proto::getValueProperty(ExecState*, int token) const\n{\n");
642       push(@implContent, "    // The token is the numeric value of its associated constant\n");
643       push(@implContent, "    return jsNumber(token);\n}\n\n");
644   }
645   
646   # - Initialize static ClassInfo object
647   push(@implContent, "const ClassInfo $className" . "::info = { \"$interfaceName\", ");
648   if ($hasParent) {
649     push(@implContent, "&" .$parentClassName . "::info, ");
650   } else {
651     push(@implContent, "0, ");
652   }
653   
654   if ($numAttributes > 0) {
655     push(@implContent, "&${className}Table, ");
656   } else {
657     push(@implContent, "0, ")
658   }
659   push(@implContent, "0 };\n\n");
660     
661   # Constructor
662   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
663       push(@implContent, "${className}::$className($implClassName* impl)\n");
664       push(@implContent, "    : $parentClassName(impl)\n");
665   } else {
666       push(@implContent, "${className}::$className(ExecState* exec, $implClassName* impl)\n");
667       if ($hasParent) {
668           push(@implContent, "    : $parentClassName(exec, impl)\n");
669       } else {
670           push(@implContent, "    : m_impl(impl)\n");
671       }
672   }
673   
674   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
675       push(@implContent, "{\n    setPrototype(${className}Proto::self());\n}\n\n");
676   } else {
677       push(@implContent, "{\n    setPrototype(${className}Proto::self(exec));\n}\n\n");
678   }
679   
680   # Destructor
681   if (!$hasParent) {
682     push(@implContent, "${className}::~$className()\n");
683     push(@implContent, "{\n    ScriptInterpreter::forgetDOMObject(m_impl.get());\n}\n\n");    
684   }
685
686   # Document needs a special destructor because it's a special case for caching. It needs
687   # its own special handling rather than relying on the caching that Node normally does.
688   if ($interfaceName eq "Document") {
689     push(@implContent, "${className}::~$className()\n");
690     push(@implContent, "{\n    ScriptInterpreter::forgetDOMObject(static_cast<${implClassName}*>(m_impl.get()));\n}\n\n");    
691   }
692   
693   # Attributes
694   if ($numAttributes ne 0) {
695     push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
696     push(@implContent, "{\n");
697     # FIXME: We need to provide scalable hooks/attributes for this kind of extension
698     if ($interfaceName eq "DOMWindow") {
699         push(@implContent, "    if (getOverridePropertySlot(exec, propertyName, slot))\n");
700         push(@implContent, "        return true;\n");
701     }
702     
703     my $hasNameGetterGeneration = sub {
704         push(@implContent, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
705         push(@implContent, "        slot.setCustom(this, nameGetter);\n");
706         push(@implContent, "        return true;\n");
707         push(@implContent, "    }\n");
708     };
709     
710     if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
711         &$hasNameGetterGeneration();
712     }
713
714     my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
715     if ($requiresManualLookup) {
716         push(@implContent, "    const HashEntry* entry = Lookup::findEntry(&${className}Table, propertyName);\n");
717         push(@implContent, "    if (entry) {\n");
718         push(@implContent, "        slot.setStaticEntry(this, entry, staticValueGetter<$className>);\n");
719         push(@implContent, "        return true;\n");
720         push(@implContent, "    }\n");
721     }
722     
723     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
724         # if it has a prototype, we need to check that first too
725         push(@implContent, "    if (prototype()->isObject() && static_cast<JSObject*>(prototype())->hasProperty(exec, propertyName))\n");
726         push(@implContent, "        return false;\n");
727     }
728     
729     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
730         push(@implContent, "    bool ok;\n");
731         push(@implContent, "    unsigned u = propertyName.toUInt32(&ok);\n");
732         push(@implContent, "    if (ok && u < static_cast<$implClassName*>(impl())->length()) {\n");
733         push(@implContent, "        slot.setCustomIndex(this, u, indexGetter);\n");
734         push(@implContent, "        return true;\n");
735         push(@implContent, "    }\n");
736     }    
737     
738     if ($dataNode->extendedAttributes->{"HasNameGetter"}) {
739         &$hasNameGetterGeneration();
740     }
741     
742     if ($requiresManualLookup) {
743         push(@implContent, "    return ${parentClassName}::getOwnPropertySlot(exec, propertyName, slot);\n");
744     } else {
745         push(@implContent, "    return getStaticValueSlot<$className, $parentClassName>(exec, &${className}Table, this, propertyName, slot);\n");
746     }
747     push(@implContent, "}\n\n");
748   
749     push(@implContent, "JSValue* ${className}::getValueProperty(ExecState* exec, int token) const\n{\n");
750     push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
751     push(@implContent, "    switch (token) {\n");
752
753     foreach my $attribute (@{$dataNode->attributes}) {
754       my $name = $attribute->signature->name;
755         
756       if ($attribute->signature->extendedAttributes->{"Custom"}) {
757         push(@implContent, "    case " . ucfirst($name) . "AttrNum:\n");
758         push(@implContent, "        return $name(exec);\n");
759       } elsif ($attribute->signature->type =~ /Constructor$/) {
760         my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
761         $constructorType =~ s/Constructor$//;
762
763         push(@implContent, "    case " . $name . "ConstructorAttrNum:\n");
764         push(@implContent, "        return JS" . $constructorType . "::getConstructor(exec);\n");
765       } elsif (!@{$attribute->getterExceptions}) {
766         push(@implContent, "    case " . ucfirst($name) . "AttrNum:\n");
767         push(@implContent, "        return " . NativeToJSValue($attribute->signature, "imp->$name()") . ";\n");
768       } else {
769         push(@implContent, "    case " . ucfirst($name) . "AttrNum: {\n");
770         push(@implContent, "        ExceptionCode ec = 0;\n");
771         push(@implContent, "        KJS::JSValue* result = " . NativeToJSValue($attribute->signature, "imp->$name(ec)") . ";\n");
772         push(@implContent, "        setDOMException(exec, ec);\n");
773         push(@implContent, "        return result;\n");
774         push(@implContent, "    }\n");
775       }
776     }
777
778     push(@implContent, "    }\n    return 0;\n}\n\n");
779     
780     # Check if we have any writable attributes
781     my $hasReadWriteProperties = 0;
782     foreach my $attribute (@{$dataNode->attributes}) {
783       $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
784     }
785     if ($hasReadWriteProperties) {
786       push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)\n");
787       if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
788         push(@implContent, "{\n" .
789                            "    if (!lookupPut<$className>(exec, propertyName, value, attr, &${className}Table, this))\n");
790         push(@implContent, "        indexSetter(exec, propertyName, value, attr);\n");
791         push(@implContent, "}\n\n");
792       }
793       else {
794         push(@implContent, "{\n    lookupPut<$className, $parentClassName>" .
795                            "(exec, propertyName, value, attr, &${className}Table, this);\n}\n\n");
796       }
797
798       push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
799       push(@implContent, "{\n");
800       push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
801       push(@implContent, "    switch (token) {\n");
802
803       foreach my $attribute (@{$dataNode->attributes}) {
804         if ($attribute->type !~ /^readonly/) {
805           my $name = $attribute->signature->name;
806  
807           if ($attribute->signature->extendedAttributes->{"Custom"}) {
808               push(@implContent, "    case " . ucfirst($name) . "AttrNum: {\n");
809               push(@implContent, "        set" . ucfirst($name) . "(exec, value);\n");
810           } elsif ($attribute->signature->type =~ /Constructor$/) {
811               my $constructorType = $attribute->signature->type;
812               $constructorType =~ s/Constructor$//;
813
814               $implIncludes{"JS" . $constructorType . ".h"} = 1;
815               push(@implContent, "    case " . $name ."ConstructorAttrNum: {\n");
816               push(@implContent, "        // Shadowing a built-in constructor\n");
817
818               # FIXME: We need to provide scalable hooks/attributes for this kind of extension
819               push(@implContent, "        if (isSafeScript(exec))\n");
820               push(@implContent, "            JSObject::put(exec, \"$name\", value);\n");
821           } else {
822               push(@implContent, "    case " . ucfirst($name) ."AttrNum: {\n");
823               push(@implContent, "        ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
824               push(@implContent, "        imp->set" . ucfirst($name) . "(" . JSValueToNative($attribute->signature, "value"));
825               push(@implContent, ", ec") if @{$attribute->setterExceptions};
826               push(@implContent, ");\n");
827               push(@implContent, "        setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
828           }
829           push(@implContent, "        break;\n");
830           push(@implContent, "    }\n");
831         }
832       }
833       push(@implContent, "    }\n"); # end switch
834         
835       if ($interfaceName eq "DOMWindow") {
836           push(@implContent, "    // FIXME: Hack to prevent unused variable warning -- remove once DOMWindow includes a settable property\n");
837           push(@implContent, "    (void)imp;\n");
838       }
839       push(@implContent, "}\n\n"); # end function
840     }
841   }
842
843   if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
844     push(@implContent, "JSValue* ${className}::getConstructor(ExecState* exec)\n{\n");
845     push(@implContent, "    return KJS::cacheGlobalObject<${className}Constructor>(exec, \"[[${interfaceName}.constructor]]\");\n");
846     push(@implContent, "}\n");
847   }    
848   
849   # Functions
850   if($numFunctions ne 0) {
851     push(@implContent, "JSValue* ${className}ProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)\n{\n");
852     push(@implContent, "    if (!thisObj->inherits(&${className}::info))\n");
853     push(@implContent, "      return throwError(exec, TypeError);\n\n");
854
855     push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(thisObj)->impl());\n\n");
856
857     push(@implContent, "    switch (id) {\n");
858     foreach my $function (@{$dataNode->functions}) {
859       push(@implContent, "    case ${className}::" . ucfirst($function->signature->name) . "FuncNum: {\n");
860
861       if ($function->signature->extendedAttributes->{"Custom"}) {
862         push(@implContent, "        return static_cast<${className}*>(thisObj)->" . $function->signature->name . "(exec, args);\n    }\n");
863         next;
864       }
865
866       AddIncludesForType($function->signature->type);
867
868       if (@{$function->raisesExceptions}) {
869         push(@implContent, "        ExceptionCode ec = 0;\n");
870       }
871
872       my $paramIndex = 0;
873       my $functionString = "imp->" . $function->signature->name . "(";
874       my $numParameters = @{$function->parameters};
875       my $hasOptionalArguments = 0;
876
877       # Special case for SVGLengthList / SVGTransformList / SVGPathSegList.
878       # These lists still use RefPtr objects, which will be changed in future.
879       # For now they need special treatment in the generation.
880       my $isRefPtr = 0;
881       if ($interfaceName eq "SVGLengthList" or
882           $interfaceName eq "SVGTransformList" or
883           $interfaceName eq "SVGPathSegList") {
884         $isRefPtr = 1;
885       }
886
887       foreach my $parameter (@{$function->parameters}) {
888         if (!$hasOptionalArguments && $parameter->extendedAttributes->{"Optional"}) {
889           push(@implContent, "\n        int argsCount = args.size();\n");
890           $hasOptionalArguments = 1;
891         }
892
893         if ($hasOptionalArguments) {
894           push(@implContent, "        if (argsCount < " . ($paramIndex + 1) . ") {\n");
895           GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    " x 3, $isRefPtr);
896           push(@implContent, "        }\n\n");
897         }
898
899         my $name = $parameter->name;
900         push(@implContent, "        bool ${name}Ok;\n") if TypeCanFailConversion($parameter);
901         push(@implContent, "        " . GetNativeType($parameter) . " $name = " . JSValueToNative($parameter, "args[$paramIndex]", TypeCanFailConversion($parameter) ? "${name}Ok" : undef) . ";\n");        
902         if (TypeCanFailConversion($parameter)) {
903           push(@implContent, "        if (!${name}Ok) {\n");
904           push(@implContent, "            setDOMException(exec, TYPE_MISMATCH_ERR);\n");
905           push(@implContent, "            return jsUndefined();\n        }\n");
906         }          
907
908         # If a parameter is "an index", it should throw an INDEX_SIZE_ERR
909         # exception        
910         if ($parameter->extendedAttributes->{"IsIndex"}) {
911           $implIncludes{"ExceptionCode.h"} = 1;
912           push(@implContent, "        if ($name < 0) {\n");
913           push(@implContent, "            setDOMException(exec, INDEX_SIZE_ERR);\n");
914           push(@implContent, "            return jsUndefined();\n        }\n");          
915         }
916
917         $functionString .= ", " if $paramIndex;
918         $functionString .= $name;
919
920         $paramIndex++;
921       }
922
923       push(@implContent, "\n");
924       GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    " x 2, $isRefPtr);
925
926       push(@implContent, "    }\n"); # end case
927     }
928     push(@implContent, "    }\n"); # end switch
929     push(@implContent, "    return 0;\n");
930     push(@implContent, "}\n");
931   }
932
933   if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
934     push(@implContent, "\nJSValue* ${className}::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot)\n");
935     push(@implContent, "{\n");
936     push(@implContent, "    ${className}* thisObj = static_cast<$className*>(slot.slotBase());\n");
937     push(@implContent, "    return toJS(exec, static_cast<$implClassName*>(thisObj->impl())->item(slot.index()));\n");
938     push(@implContent, "}\n");
939   }
940
941   if (!$hasParent) {
942     my $implContent = << "EOF";
943 KJS::JSValue* toJS(KJS::ExecState* exec, $implClassName* obj)
944 {
945     return KJS::cacheDOMObject<$implClassName, $className>(exec, obj);
946 }
947 EOF
948     push(@implContent, $implContent);
949    }
950
951    if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
952     my $implContent = << "EOF";
953 $implClassName* to${interfaceName}(KJS::JSValue* val)
954 {
955     return val->isObject(&${className}::info) ? static_cast<$className*>(val)->impl() : 0;
956 }
957 EOF
958     push(@implContent, $implContent);
959   }
960   
961   if ($dataNode->extendedAttributes->{"GenerateNativeConverter"} && $hasParent) {
962     push(@implContent, "\n$implClassName* ${className}::impl() const\n");
963     push(@implContent, "{\n");
964     push(@implContent, "    return static_cast<$implClassName*>(${parentClassName}::impl());\n");
965     push(@implContent, "}\n");
966   }
967
968   push(@implContent, "\n}\n");
969     
970   push(@implContent, "\n#endif // ${conditional}_SUPPORT\n") if $conditional;
971 }
972
973 sub GenerateImplementationFunctionCall()
974 {
975     my $function = shift;
976     my $functionString = shift;
977     my $paramIndex = shift;
978     my $indent = shift;
979     my $isRefPtr = shift;
980
981     if (@{$function->raisesExceptions}) {
982         $functionString .= ", " if $paramIndex;
983         $functionString .= "ec";
984     }
985     $functionString .= ")";
986
987     if ($function->signature->type eq "void") {
988         push(@implContent, $indent . "$functionString;\n");
989         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
990         push(@implContent, $indent . "return jsUndefined();\n");
991     } else {
992         push(@implContent, "\n" . $indent . "KJS::JSValue* result = " . NativeToJSValue($function->signature, $functionString, $isRefPtr) . ";\n");
993         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
994         push(@implContent, $indent . "return result;\n");
995     }
996 }
997
998 sub GetNativeType
999 {
1000     my $signature = shift;
1001     
1002     my $type = $codeGenerator->StripModule($signature->type);
1003     
1004     if ($type eq "boolean") {
1005         return "bool";
1006     } elsif ($type eq "unsigned long") {
1007         if ($signature->extendedAttributes->{"IsIndex"}) {
1008             # Special-case index arguments because we need to check that
1009             # they aren't < 0.        
1010             return "int";
1011         } else {
1012             return "unsigned";
1013         } 
1014     } elsif ($type eq "long") {
1015         return "int";
1016     } elsif ($type eq "unsigned short" or $type eq "float") {
1017         return $type;
1018     } elsif ($type eq "AtomicString") {
1019         return "AtomicString";
1020     } elsif ($type eq "DOMString") {
1021         return "String";
1022     } elsif ($type eq "NodeFilter") {
1023         return "PassRefPtr<${type}>";
1024     } elsif ($type eq "CompareHow") {
1025         return "Range::CompareHow";
1026     } elsif ($type eq "EventTarget") {
1027         return "EventTargetNode*";
1028     } elsif ($type eq "SVGRect") {
1029         return "FloatRect";
1030     } elsif ($type eq "SVGPoint") {
1031         return "FloatPoint";
1032     } elsif ($type eq "SVGNumber") {
1033         return "double";
1034     } elsif($type eq "SVGPaintType") {
1035         return "SVGPaint::SVGPaintType";
1036     }
1037
1038     # Default, assume native type is a pointer with same type name as idl type
1039     return "${type}*";
1040 }
1041
1042 sub TypeCanFailConversion
1043 {
1044   my $signature = shift;
1045   
1046   my $type = $codeGenerator->StripModule($signature->type);
1047
1048   if ($type eq "boolean") {
1049     return 0;
1050   } elsif ($type eq "unsigned long" or $type eq "long") {
1051     $implIncludes{"ExceptionCode.h"} = 1;
1052     return 1;
1053   } elsif ($type eq "unsigned short") {
1054     return 0; # or can it?
1055   } elsif ($type eq "CompareHow") {
1056     return 0; # or can it?
1057   } elsif ($type eq "float") {
1058     return 0;
1059   } elsif ($type eq "Attr") {
1060       $implIncludes{"ExceptionCode.h"} = 1;
1061       return 1;
1062   } elsif ($type eq "AtomicString" or
1063            $type eq "DOMString" or
1064            $type eq "Node" or
1065            $type eq "Element" or
1066            $type eq "DocumentType" or
1067            $type eq "EventTarget" or
1068            $type eq "Range" or
1069            $type eq "NodeFilter" or
1070            $type eq "DOMWindow" or
1071            $type eq "XPathEvaluator" or
1072            $type eq "XPathNSResolver" or
1073            $type eq "XPathResult" or
1074            $type eq "SVGAngle" or
1075            $type eq "SVGLength" or
1076            $type eq "SVGNumber" or
1077            $type eq "SVGPoint" or
1078            $type eq "SVGTransform" or
1079            $type eq "SVGPathSeg" or
1080            $type eq "SVGMatrix" or
1081            $type eq "SVGRect" or
1082            $type eq "SVGElement" or
1083            $type eq "HTMLOptionElement") {
1084       return 0;
1085   } elsif ($type eq "SVGPaintType") {
1086     return 0; # or can it?
1087   } else {
1088     die "Don't know whether a JS value can fail conversion to type $type."
1089   }
1090 }
1091
1092 sub JSValueToNative
1093 {
1094     my $signature = shift;
1095     my $value = shift;
1096     my $okParam = shift;
1097     my $maybeOkParam = $okParam ? ", ${okParam}" : "";
1098     
1099     my $type = $codeGenerator->StripModule($signature->type);
1100     
1101     if ($type eq "boolean") {
1102         return "$value->toBoolean(exec)";
1103     } elsif ($type eq "unsigned long" or
1104              $type eq "long" or
1105              $type eq "unsigned short") {
1106         if ($maybeOkParam) {
1107             return "$value->toInt32(exec${maybeOkParam})";
1108         } else {
1109             return "$value->toInt32(exec)";
1110         }
1111     } elsif ($type eq "CompareHow") {
1112         return "static_cast<Range::CompareHow>($value->toInt32(exec))";
1113     } elsif ($type eq "float") {
1114         return "$value->toNumber(exec)";
1115     } elsif ($type eq "AtomicString") {
1116         return "$value->toString(exec)";
1117     } elsif ($type eq "DOMString") {
1118         if ($signature->extendedAttributes->{"ConvertNullToNullString"}) {
1119             return "valueToStringWithNullCheck(exec, $value)";
1120         } else {
1121             return "$value->toString(exec)";
1122         }
1123     } elsif ($type eq "Node") {
1124         $implIncludes{"kjs_dom.h"} = 1;
1125         return "toNode($value)";
1126     } elsif ($type eq "EventTarget") {
1127         $implIncludes{"kjs_dom.h"} = 1;
1128         return "toEventTargetNode($value)";
1129     }  elsif ($type eq "Attr") {
1130         $implIncludes{"kjs_dom.h"} = 1;
1131         return "toAttr($value${maybeOkParam})";
1132     } elsif ($type eq "DocumentType") {
1133         $implIncludes{"kjs_dom.h"} = 1;
1134         return "toDocumentType($value)";
1135     } elsif ($type eq "Element") {
1136         $implIncludes{"kjs_dom.h"} = 1;
1137         return "toElement($value)";
1138     } elsif ($type eq "NodeFilter") {
1139         $implIncludes{"kjs_traversal.h"} = 1;
1140         return "toNodeFilter($value)";
1141     } elsif ($type eq "DOMWindow") {
1142         $implIncludes{"kjs_window.h"} = 1;
1143         return "toDOMWindow($value)";
1144     } elsif ($type eq "SVGRect") {
1145         $implIncludes{"JSSVGRect.h"} = 1;
1146         return "toFloatRect($value)";
1147     } elsif ($type eq "SVGPoint") {
1148         $implIncludes{"JSSVGPoint.h"} = 1;
1149         return "toFloatPoint($value)";
1150     } elsif ($type eq "SVGNumber") {
1151         return "$value->toNumber(exec)";
1152     } elsif ($type eq "SVGPaintType") {
1153         return "static_cast<SVGPaint::SVGPaintType>($value->toInt32(exec))";
1154     }
1155
1156     # Default, assume autogenerated type conversion routines
1157     $implIncludes{"JS$type.h"} = 1;
1158     return "to$type($value)";
1159 }
1160
1161 sub NativeToJSValue
1162 {
1163     my $signature = shift;
1164     my $value = shift;
1165     my $isRefPtr = shift;
1166  
1167     my $type = $codeGenerator->StripModule($signature->type);
1168
1169     if ($type eq "boolean") {
1170         return "jsBoolean($value)";
1171     } elsif ($type eq "long" or
1172              $type eq "unsigned long" or 
1173              $type eq "short" or 
1174              $type eq "unsigned short" or
1175              $type eq "float" or 
1176              $type eq "double") {
1177         return "jsNumber($value)";
1178     } elsif ($type eq "DOMString" or $type eq "AtomicString") {
1179         my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
1180         if (defined $conv) {
1181             if ($conv eq "Null") {
1182                 return "jsStringOrNull($value)";
1183             } elsif ($conv eq "Undefined") {
1184                 return "jsStringOrUndefined($value)";
1185             } elsif ($conv eq "False") {
1186                 return "jsStringOrFalse($value)";
1187             } else {
1188                 die "Unknown value for ConvertNullStringTo extended attribute";
1189             }
1190         } else {
1191             return "jsString($value)";
1192         }
1193     } elsif ($type eq "DOMImplementation") {
1194         $implIncludes{"kjs_dom.h"} = 1;
1195         $implIncludes{"JSDOMImplementation.h"} = 1;
1196         return "toJS(exec, $value)";
1197     } elsif ($type eq "Attr" or
1198              $type eq "CDATASection" or
1199              $type eq "Comment" or
1200              $type eq "Document" or
1201              $type eq "DocumentFragment" or
1202              $type eq "DocumentType" or
1203              $type eq "Element" or
1204              $type eq "EntityReference" or
1205              $type eq "HTMLDocument" or
1206              $type eq "Node" or
1207              $type eq "ProcessingInstruction" or
1208              $type eq "Text") {
1209         $implIncludes{"kjs_dom.h"} = 1;
1210         $implIncludes{"Comment.h"} = 1;
1211         $implIncludes{"CDATASection.h"} = 1;
1212         $implIncludes{"Node.h"} = 1;
1213         $implIncludes{"Element.h"} = 1;
1214         $implIncludes{"DocumentType.h"} = 1;
1215         return "toJS(exec, $value)";
1216     } elsif ($type eq "EventTarget") {
1217         $implIncludes{"kjs_dom.h"} = 1;
1218         $implIncludes{"EventTargetNode.h"} = 1;
1219         return "toJS(exec, $value)";
1220     } elsif ($type eq "Event") {
1221         $implIncludes{"kjs_events.h"} = 1;
1222         $implIncludes{"Event.h"} = 1;
1223         return "toJS(exec, $value)";
1224     } elsif ($type eq "NodeList" or $type eq "NamedNodeMap") {
1225         $implIncludes{"kjs_dom.h"} = 1;
1226         return "toJS(exec, $value)";
1227     } elsif ($type eq "CSSStyleSheet" or $type eq "StyleSheet" or $type eq "MediaList") {
1228         $implIncludes{"CSSStyleSheet.h"} = 1;
1229         $implIncludes{"MediaList.h"} = 1;
1230         $implIncludes{"kjs_css.h"} = 1;
1231         return "toJS(exec, $value)";
1232     } elsif ($type eq "StyleSheetList") {
1233         $implIncludes{"StyleSheetList.h"} = 1;
1234         $implIncludes{"kjs_css.h"} = 1;
1235         return "toJS(exec, $value, imp)";
1236     } elsif ($type eq "CSSStyleDeclaration" or $type eq "Rect") {
1237         $implIncludes{"CSSStyleDeclaration.h"} = 1;
1238         $implIncludes{"RectImpl.h"} = 1;
1239         $implIncludes{"kjs_css.h"} = 1;
1240         return "toJS(exec, $value)";
1241     } elsif ($type eq "RGBColor") {
1242         $implIncludes{"kjs_css.h"} = 1;
1243         return "getDOMRGBColor(exec, $value)";
1244     } elsif ($type eq "HTMLCanvasElement") {
1245         $implIncludes{"kjs_dom.h"} = 1;
1246         $implIncludes{"HTMLCanvasElement.h"} = 1;
1247         return "toJS(exec, $value)";
1248     } elsif ($type eq "DOMWindow") {
1249         $implIncludes{"kjs_window.h"} = 1;
1250         return "toJS(exec, $value)";
1251     } elsif ($type eq "DOMObject") {
1252         $implIncludes{"JSCanvasRenderingContext2D.h"} = 1;
1253         return "toJS(exec, $value)";
1254     } elsif ($type eq "HTMLFormElement") {
1255         $implIncludes{"kjs_html.h"} = 1;
1256         $implIncludes{"HTMLFormElement.h"} = 1;
1257         return "toJS(exec, $value)";
1258     } elsif ($type eq "HTMLCollection") {
1259         $implIncludes{"kjs_html.h"} = 1;
1260         $implIncludes{"HTMLCollection.h"} = 1;
1261         return "getHTMLCollection(exec, $value.get())";
1262     } elsif (($type eq "SVGLength" or
1263               $type eq "SVGTransform") and $isRefPtr eq 1) {
1264        $implIncludes{"JS$type.h"} = 1;
1265        $implIncludes{"$type.h"} = 1;
1266        return "toJS(exec, $value.get())";
1267     } elsif ($type eq "SVGRect" or
1268              $type eq "SVGPoint" or
1269              $type eq "SVGNumber") {
1270         $implIncludes{"JS$type.h"} = 1;
1271         return "getJS$type(exec, $value)";
1272     } elsif ($type =~ /SVGPathSeg/) {
1273         $implIncludes{"JS$type.h"} = 1;
1274         $joinedName = $type;
1275         $joinedName =~ s/Abs|Rel//;
1276         $implIncludes{"$joinedName.h"} = 1;
1277
1278         if ($isRefPtr eq 1) {
1279             return "toJS(exec, $value.get())";
1280         } else {
1281             return "toJS(exec, $value)";
1282         }
1283     } elsif ($codeGenerator->IsSVGAnimatedType($type)) {
1284         $implIncludes{"JS$type.h"} = 1;
1285         $implIncludes{"$type.h"} = 1;
1286         $tempValue = $value;
1287         $tempValue =~ s/\(\)//;
1288         $tempValue .= "Animated()";
1289         return "toJS(exec, $tempValue)";
1290     } elsif ($type eq "SVGPaintType") {
1291         return "jsNumber($value)";
1292     }
1293
1294     # Default, include header with same name.
1295     $implIncludes{"JS$type.h"} = 1;
1296     $implIncludes{"$type.h"} = 1;
1297     return "toJS(exec, $value)";
1298 }
1299
1300 # Internal Helper
1301 sub GenerateHashTable
1302 {
1303     my $object = shift;
1304     
1305     my $name = shift;
1306     my $size = shift;
1307     my $keys = shift;
1308     my $values = shift;
1309     my $specials = shift;
1310     my $parameters = shift;
1311     
1312     # Helpers
1313     my @table = ();
1314     my @links = ();
1315     
1316     my $maxDepth = 0;
1317     my $collisions = 0;
1318     my $numEntries = $size;
1319     
1320     # Collect hashtable information
1321     my $i = 0;
1322     foreach(@{$keys}) {
1323         my $depth = 0;
1324         my $h = $object->GenerateHashValue($_) % $numEntries;
1325         
1326         while(defined($table[$h])) {
1327             if (defined($links[$h])) {
1328                 $h = $links[$h];
1329                 $depth++;
1330             } else {
1331                 $collisions++;
1332                 $links[$h] = $size;
1333                 $h = $size;
1334                 $size++;
1335             }
1336         }
1337         
1338         $table[$h] = $i;
1339         
1340         $i++;
1341         $maxDepth = $depth if ($depth > $maxDepth);
1342     }
1343     
1344     # Ensure table is big enough (in case of undef entries at the end)
1345     if ($#table + 1 < $size) {
1346         $#table = $size - 1;
1347     }
1348     
1349     # Start outputing the hashtables
1350     my $nameEntries = "${name}Entries";
1351     $nameEntries =~ s/:/_/g;
1352     
1353     # first, build the string table
1354     my %soffset = ();
1355     if (($name =~ /Proto/) or ($name =~ /Constructor/)) {
1356         my $type = $name;
1357         my $implClass;
1358         
1359         if ($name =~ /Proto/) {
1360             $type =~ s/Proto.*//;
1361             $implClass = $type; $implClass =~ s/Wrapper$//;
1362             push(@implContent, "/* Hash table for prototype */\n");
1363         } else {
1364             $type =~ s/Constructor.*//;
1365             $implClass = $type; $implClass =~ s/Constructor$//;
1366             push(@implContent, "/* Hash table for constructor */\n");
1367         }
1368     } else {
1369         push(@implContent, "/* Hash table */\n");
1370     }
1371     
1372     # Dump the hash table
1373     push(@implContent, "\nstatic const HashEntry $nameEntries\[\] =\n\{\n");
1374     
1375     $i = 0;
1376     foreach $entry (@table) {
1377         if (defined($entry)) {
1378             my $key = @$keys[$entry];
1379             
1380             push(@implContent, "    \{ \"" . $key . "\"");
1381             push(@implContent, ", " . @$values[$entry]);
1382             push(@implContent, ", " . @$specials[$entry]);
1383             push(@implContent, ", " . @$parameters[$entry]);
1384             push(@implContent, ", ");
1385             
1386             if (defined($links[$i])) {
1387                 push(@implContent, "&${nameEntries}[$links[$i]]" . " \}");
1388             } else {
1389                 push(@implContent, "0 \}");
1390             }
1391         } else {
1392             push(@implContent, "    \{ 0, 0, 0, 0, 0 \}");
1393         }
1394         
1395         push(@implContent, ",") unless($i eq $size - 1);
1396         push(@implContent, "\n");
1397         
1398         $i++;
1399     }
1400     
1401     if ($size eq 0) {
1402         # dummy bucket -- an empty table would crash Lookup::findEntry
1403         push(@implContent, "    \{ 0, 0, 0, 0, 0 \}\n") ;
1404         $numEntries = 1;
1405         $size = 1;
1406     }
1407     push(@implContent, "};\n\n");
1408     push(@implContent, "static const HashTable $name = \n");
1409     push(@implContent, "{\n    2, $size, $nameEntries, $numEntries\n};\n\n");
1410 }
1411
1412 # Internal helper
1413 sub GenerateHashValue
1414 {
1415     my $object = shift;
1416     
1417     @chars = split(/ */, $_[0]);
1418     
1419     # This hash is designed to work on 16-bit chunks at a time. But since the normal case
1420     # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
1421     # were 16-bit chunks, which should give matching results
1422     
1423     my $EXP2_32 = 4294967296;
1424     
1425     my $hash = 0x9e3779b9;
1426     my $l    = scalar @chars; #I wish this was in Ruby --- Maks
1427     my $rem  = $l & 1;
1428     $l = $l >> 1;
1429     
1430     my $s = 0;
1431     
1432     # Main loop
1433     for (; $l > 0; $l--) {
1434         $hash   += ord($chars[$s]);
1435         my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
1436         $hash   = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
1437         $s += 2;
1438         $hash += $hash >> 11;
1439     }
1440     
1441     # Handle end case
1442     if ($rem !=0) {
1443         $hash += ord($chars[$s]);
1444         $hash ^= (leftShift($hash, 11)% $EXP2_32);
1445         $hash += $hash >> 17;
1446     }
1447     
1448     # Force "avalanching" of final 127 bits
1449     $hash ^= leftShift($hash, 3);
1450     $hash += ($hash >> 5);
1451     $hash = ($hash% $EXP2_32);
1452     $hash ^= (leftShift($hash, 2)% $EXP2_32);
1453     $hash += ($hash >> 15);
1454     $hash = $hash% $EXP2_32;
1455     $hash ^= (leftShift($hash, 10)% $EXP2_32);
1456     
1457     # this avoids ever returning a hash code of 0, since that is used to
1458     # signal "hash not computed yet", using a value that is likely to be
1459     # effectively the same as 0 when the low bits are masked
1460     $hash = 0x80000000  if ($hash == 0);
1461     
1462     return $hash;
1463 }
1464
1465 # Internal helper
1466 sub WriteData
1467 {
1468     if (defined($IMPL)) {
1469         # Write content to file.
1470         print $IMPL @implContentHeader;
1471         
1472         foreach my $implInclude (sort keys(%implIncludes)) {
1473             my $checkType = $implInclude;
1474             $checkType =~ s/\.h//;
1475     
1476             print $IMPL "#include \"$implInclude\"\n" unless($codeGenerator->IsSVGAnimatedType($checkType));
1477         }
1478         
1479         print $IMPL @implContent;
1480         close($IMPL);
1481         undef($IMPL);
1482         
1483         @implHeaderContent = "";
1484         @implContent = "";    
1485         %implIncludes = ();
1486     }
1487         
1488     if (defined($HEADER)) {
1489         # Write content to file.
1490         print $HEADER @headerContent;
1491         close($HEADER);
1492         undef($HEADER);
1493         
1494         @headerContent = "";
1495     }
1496 }
1497
1498 sub constructorFor
1499 {
1500     my $className = shift;
1501     my $protoClassName = shift;
1502     my $interfaceName = shift;
1503     my $canConstruct = shift;
1504     
1505 my $implContent = << "EOF";
1506 class ${className}Constructor : public DOMObject {
1507 public:
1508     ${className}Constructor(ExecState* exec) 
1509     { 
1510         setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); 
1511         putDirect(prototypePropertyName, ${protoClassName}::self(exec), None);
1512     }
1513     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
1514     JSValue* getValueProperty(ExecState*, int token) const;
1515     virtual const ClassInfo* classInfo() const { return &info; }
1516     static const ClassInfo info;
1517 EOF
1518
1519     if ($canConstruct) {
1520 $implContent .= << "EOF";
1521     virtual bool implementsConstruct() const { return true; }
1522     virtual JSObject* construct(ExecState* exec, const List& args) { return static_cast<JSObject*>(toJS(exec, new $interfaceName)); }
1523 EOF
1524     }
1525
1526 $implContent .= << "EOF";
1527 };
1528
1529 const ClassInfo ${className}Constructor::info = { "${interfaceName}Constructor", 0, &${className}ConstructorTable, 0 };
1530
1531 bool ${className}Constructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1532 {
1533     return getStaticValueSlot<${className}Constructor, DOMObject>(exec, &${className}ConstructorTable, this, propertyName, slot);
1534 }
1535
1536 JSValue* ${className}Constructor::getValueProperty(ExecState*, int token) const
1537 {
1538     // The token is the numeric value of its associated constant
1539     return jsNumber(token);
1540 }
1541
1542 EOF
1543
1544     return $implContent;
1545 }
1546
1547 sub protoFuncFor
1548 {
1549     my $className = shift;
1550     
1551 my $implContent = << "EOF";
1552 class ${className}ProtoFunc : public InternalFunctionImp {
1553 public:
1554     ${className}ProtoFunc(ExecState* exec, int i, int len, const Identifier& name)
1555     : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
1556     , id(i)
1557     {
1558         put(exec, lengthPropertyName, jsNumber(len), DontDelete|ReadOnly|DontEnum);
1559     }
1560     virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List& args);
1561 private:
1562     int id;
1563 };
1564
1565 EOF
1566   
1567     return $implContent;
1568 }
1569
1570 1;