75da7698dd3c7d0d5bad3cb668b5aab1693395cf
[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     if (!$dataNode->extendedAttributes->{"DoNotCache"}) {
432         push(@headerContent, "    friend KJS::JSObject* KJS_GCC_ROOT_NS_HACK cacheGlobalObject<${className}Proto>(KJS::ExecState*, const KJS::Identifier& propertyName);\n");
433     }
434     push(@headerContent, "public:\n");
435     if ($dataNode->extendedAttributes->{"DoNotCache"}) {
436         push(@headerContent, "    static KJS::JSObject* self();\n");
437     } else {
438         push(@headerContent, "    static KJS::JSObject* self(KJS::ExecState* exec);\n");
439     }
440     push(@headerContent, "    virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
441     push(@headerContent, "    static const KJS::ClassInfo info;\n");
442     if ($numFunctions > 0 || $numConstants > 0) {
443         push(@headerContent, "    bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
444     }
445     if ($numConstants ne 0) {
446         push(@headerContent, "    KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
447     }
448     push(@headerContent, "protected:\n");
449     if ($dataNode->extendedAttributes->{"DoNotCache"}) {
450         push(@headerContent, "    ${className}Proto() { }\n");
451     } else {
452         push(@headerContent, "    ${className}Proto(KJS::ExecState* exec)\n");
453         if ($hasParent && $parentClassName ne "KJS::DOMCSSRule" && $parentClassName ne "KJS::DOMNodeFilter") {
454             push(@headerContent, "        : KJS::JSObject(${parentClassName}Proto::self(exec)) { }\n");
455         } else {
456             push(@headerContent, "        : KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { }\n");
457         }
458     }
459     
460     push(@headerContent, "};\n\n");
461     
462     push(@headerContent, "}\n\n");
463     
464     push(@headerContent, "#endif // ${conditional}_SUPPORT\n\n") if $conditional;
465     
466     push(@headerContent, "#endif\n");
467 }
468
469 sub GenerateImplementation
470 {
471   my $object = shift;
472   my $dataNode = shift;
473
474   my $interfaceName = $dataNode->name;
475   my $className = "JS$interfaceName";
476   my $implClassName = $interfaceName;
477   
478   my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
479   my $hasRealParent = @{$dataNode->parents} > 0;
480   my $hasParent = $hasLegacyParent || $hasRealParent;
481   my $parentClassName = GetParentClassName($dataNode);
482   my $conditional = $dataNode->extendedAttributes->{"Conditional"};
483   
484   # - Add default header template
485   @implContentHeader = split("\r", $headerTemplate);
486   push(@implContentHeader, "\n");
487   push(@implContentHeader,, "#include \"config.h\"\n\n");
488   
489   push(@implContentHeader, "#ifdef ${conditional}_SUPPORT\n\n") if $conditional;
490
491   if ($className =~ /^JSSVGAnimated/) {
492     AddIncludesForSVGAnimatedType($interfaceName);
493   }
494   
495   push(@implContentHeader, "#include \"SVGAnimatedTemplate.h\"\n") if($className =~ /SVG/);
496   push(@implContentHeader, "#include \"$className.h\"\n\n");
497  
498   AddIncludesForType($interfaceName);
499
500   @implContent = ();
501
502   push(@implContent, "\nusing namespace KJS;\n\n");  
503   push(@implContent, "namespace WebCore {\n\n");
504   
505   # - Add all attributes in a hashtable definition
506   my $numAttributes = @{$dataNode->attributes};
507   if ($numAttributes > 0) {
508     my $hashSize = $numAttributes;
509     my $hashName = $className . "Table";
510
511     my @hashKeys = ();      # ie. 'insertBefore'
512     my @hashValues = ();    # ie. 'JSNode::InsertBefore'
513     my @hashSpecials = ();    # ie. 'DontDelete|Function'
514     my @hashParameters = ();  # ie. '2'
515
516     foreach my $attribute (@{$dataNode->attributes}) {
517       my $name = $attribute->signature->name;
518       push(@hashKeys, $name);
519       
520       my $value = $className . "::" . ($attribute->signature->type =~ /Constructor$/ 
521                                        ? $attribute->signature->name . "ConstructorAttrNum" 
522                                        : ucfirst($attribute->signature->name) . "AttrNum");      
523       push(@hashValues, $value);
524
525       my $special = "DontDelete";
526       $special .= "|ReadOnly" if($attribute->type =~ /readonly/);
527       push(@hashSpecials, $special);
528
529       my $numParameters = "0";
530       push(@hashParameters, $numParameters);      
531     }
532
533     $object->GenerateHashTable($hashName, $hashSize,
534                                \@hashKeys, \@hashValues,
535                                \@hashSpecials, \@hashParameters);
536   }
537   
538   my $numConstants = @{$dataNode->constants};
539   my $numFunctions = @{$dataNode->functions};
540
541   # - Add all constants
542   if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
543     $hashSize = $numConstants;
544     $hashName = $className . "ConstructorTable";
545
546     @hashKeys = ();
547     @hashValues = ();
548     @hashSpecials = ();
549     @hashParameters = ();
550
551     foreach my $constant (@{$dataNode->constants}) {
552       my $name = $constant->name;
553       push(@hashKeys, $name);
554       
555       my $value = "${implClassName}::$name";
556       push(@hashValues, $value);
557       
558       my $special = "DontDelete|ReadOnly";
559       push(@hashSpecials, $special);
560       
561       my $numParameters = 0;
562       push(@hashParameters, $numParameters); 
563     }
564
565     $object->GenerateHashTable($hashName, $hashSize,
566                                \@hashKeys, \@hashValues,
567                                \@hashSpecials, \@hashParameters);
568
569     my $protoClassName;
570     $protoClassName = "${className}Proto";
571
572     push(@implContent, constructorFor($className, $protoClassName, $interfaceName, $dataNode->extendedAttributes->{"CanBeConstructed"}));
573   }
574   
575   # - Add functions and constants to a hashtable definition
576   $hashSize = $numFunctions + $numConstants;
577   $hashName = $className . "ProtoTable";
578
579   @hashKeys = ();
580   @hashValues = ();
581   @hashSpecials = ();
582   @hashParameters = ();
583
584   foreach my $constant (@{$dataNode->constants}) {
585       my $name = $constant->name;
586       push(@hashKeys, $name);
587         
588       my $value = "${implClassName}::$name";
589       push(@hashValues, $value);
590         
591       my $special = "DontDelete|ReadOnly";
592       push(@hashSpecials, $special);
593         
594       my $numParameters = 0;
595       push(@hashParameters, $numParameters); 
596   }
597     
598   foreach my $function (@{$dataNode->functions}) {
599     my $name = $function->signature->name;
600     push(@hashKeys, $name);
601     
602     my $value = $className . "::" . ucfirst($name) . "FuncNum";
603     push(@hashValues, $value);
604     
605     my $special = "DontDelete|Function";
606     push(@hashSpecials, $special);
607     
608     my $numParameters = @{$function->parameters};
609     push(@hashParameters, $numParameters);
610   }
611     
612   $object->GenerateHashTable($hashName, $hashSize,
613                              \@hashKeys, \@hashValues,
614                              \@hashSpecials, \@hashParameters);
615
616   if($numFunctions > 0) {
617       push(@implContent, protoFuncFor($className));
618   }
619
620   push(@implContent, "const ClassInfo ${className}Proto::info = { \"$interfaceName\", 0, &${className}ProtoTable, 0 };\n\n");
621   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
622       push(@implContent, "JSObject* ${className}Proto::self()\n");
623       push(@implContent, "{\n");
624       push(@implContent, "    return new ${className}Proto();\n");
625       push(@implContent, "}\n\n");
626   } else {
627       push(@implContent, "JSObject* ${className}Proto::self(ExecState* exec)\n");
628       push(@implContent, "{\n");
629       push(@implContent, "    return ::cacheGlobalObject<${className}Proto>(exec, \"[[${className}.prototype]]\");\n");
630       push(@implContent, "}\n\n");
631   }
632   if ($numConstants > 0 || $numFunctions > 0) {
633       push(@implContent, "bool ${className}Proto::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
634       push(@implContent, "{\n");
635       if ($numConstants eq 0) {
636           push(@implContent, "    return getStaticFunctionSlot<${className}ProtoFunc, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
637       } elsif ($numFunctions eq 0) {
638           push(@implContent, "    return getStaticValueSlot<${className}Proto, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
639       } else {
640           push(@implContent, "    return getStaticPropertySlot<${className}ProtoFunc, ${className}Proto, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
641       }
642       push(@implContent, "}\n\n");
643   }
644   if ($numConstants ne 0) {
645       push(@implContent, "JSValue* ${className}Proto::getValueProperty(ExecState*, int token) const\n{\n");
646       push(@implContent, "    // The token is the numeric value of its associated constant\n");
647       push(@implContent, "    return jsNumber(token);\n}\n\n");
648   }
649   
650   # - Initialize static ClassInfo object
651   push(@implContent, "const ClassInfo $className" . "::info = { \"$interfaceName\", ");
652   if ($hasParent) {
653     push(@implContent, "&" .$parentClassName . "::info, ");
654   } else {
655     push(@implContent, "0, ");
656   }
657   
658   if ($numAttributes > 0) {
659     push(@implContent, "&${className}Table, ");
660   } else {
661     push(@implContent, "0, ")
662   }
663   push(@implContent, "0 };\n\n");
664     
665   # Constructor
666   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
667       push(@implContent, "${className}::$className($implClassName* impl)\n");
668       push(@implContent, "    : $parentClassName(impl)\n");
669   } else {
670       push(@implContent, "${className}::$className(ExecState* exec, $implClassName* impl)\n");
671       if ($hasParent) {
672           push(@implContent, "    : $parentClassName(exec, impl)\n");
673       } else {
674           push(@implContent, "    : m_impl(impl)\n");
675       }
676   }
677   
678   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
679       push(@implContent, "{\n    setPrototype(${className}Proto::self());\n}\n\n");
680   } else {
681       push(@implContent, "{\n    setPrototype(${className}Proto::self(exec));\n}\n\n");
682   }
683   
684   # Destructor
685   if (!$hasParent) {
686     push(@implContent, "${className}::~$className()\n");
687     push(@implContent, "{\n    ScriptInterpreter::forgetDOMObject(m_impl.get());\n}\n\n");    
688   }
689
690   # Document needs a special destructor because it's a special case for caching. It needs
691   # its own special handling rather than relying on the caching that Node normally does.
692   if ($interfaceName eq "Document") {
693     push(@implContent, "${className}::~$className()\n");
694     push(@implContent, "{\n    ScriptInterpreter::forgetDOMObject(static_cast<${implClassName}*>(m_impl.get()));\n}\n\n");    
695   }
696   
697   # Attributes
698   if ($numAttributes ne 0) {
699     push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
700     push(@implContent, "{\n");
701     # FIXME: We need to provide scalable hooks/attributes for this kind of extension
702     if ($interfaceName eq "DOMWindow") {
703         push(@implContent, "    if (getOverridePropertySlot(exec, propertyName, slot))\n");
704         push(@implContent, "        return true;\n");
705     }
706     
707     my $hasNameGetterGeneration = sub {
708         push(@implContent, "    if (canGetItemsForName(exec, static_cast<$implClassName*>(impl()), propertyName)) {\n");
709         push(@implContent, "        slot.setCustom(this, nameGetter);\n");
710         push(@implContent, "        return true;\n");
711         push(@implContent, "    }\n");
712     };
713     
714     if ($dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
715         &$hasNameGetterGeneration();
716     }
717
718     my $requiresManualLookup = $dataNode->extendedAttributes->{"HasIndexGetter"} || $dataNode->extendedAttributes->{"HasNameGetter"};
719     if ($requiresManualLookup) {
720         push(@implContent, "    const HashEntry* entry = Lookup::findEntry(&${className}Table, propertyName);\n");
721         push(@implContent, "    if (entry) {\n");
722         push(@implContent, "        slot.setStaticEntry(this, entry, staticValueGetter<$className>);\n");
723         push(@implContent, "        return true;\n");
724         push(@implContent, "    }\n");
725     }
726     
727     if ($dataNode->extendedAttributes->{"HasNameGetter"} || $dataNode->extendedAttributes->{"HasOverridingNameGetter"}) {
728         # if it has a prototype, we need to check that first too
729         push(@implContent, "    if (prototype()->isObject() && static_cast<JSObject*>(prototype())->hasProperty(exec, propertyName))\n");
730         push(@implContent, "        return false;\n");
731     }
732     
733     if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
734         push(@implContent, "    bool ok;\n");
735         push(@implContent, "    unsigned u = propertyName.toUInt32(&ok);\n");
736         push(@implContent, "    if (ok && u < static_cast<$implClassName*>(impl())->length()) {\n");
737         push(@implContent, "        slot.setCustomIndex(this, u, indexGetter);\n");
738         push(@implContent, "        return true;\n");
739         push(@implContent, "    }\n");
740     }    
741     
742     if ($dataNode->extendedAttributes->{"HasNameGetter"}) {
743         &$hasNameGetterGeneration();
744     }
745     
746     if ($requiresManualLookup) {
747         push(@implContent, "    return ${parentClassName}::getOwnPropertySlot(exec, propertyName, slot);\n");
748     } else {
749         push(@implContent, "    return getStaticValueSlot<$className, $parentClassName>(exec, &${className}Table, this, propertyName, slot);\n");
750     }
751     push(@implContent, "}\n\n");
752   
753     push(@implContent, "JSValue* ${className}::getValueProperty(ExecState* exec, int token) const\n{\n");
754     push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
755     push(@implContent, "    switch (token) {\n");
756
757     foreach my $attribute (@{$dataNode->attributes}) {
758       my $name = $attribute->signature->name;
759         
760       if ($attribute->signature->extendedAttributes->{"Custom"}) {
761         push(@implContent, "    case " . ucfirst($name) . "AttrNum:\n");
762         push(@implContent, "        return $name(exec);\n");
763       } elsif ($attribute->signature->type =~ /Constructor$/) {
764         my $constructorType = $codeGenerator->StripModule($attribute->signature->type);
765         $constructorType =~ s/Constructor$//;
766
767         push(@implContent, "    case " . $name . "ConstructorAttrNum:\n");
768         push(@implContent, "        return JS" . $constructorType . "::getConstructor(exec);\n");
769       } elsif (!@{$attribute->getterExceptions}) {
770         push(@implContent, "    case " . ucfirst($name) . "AttrNum:\n");
771         push(@implContent, "        return " . NativeToJSValue($attribute->signature, "imp->$name()") . ";\n");
772       } else {
773         push(@implContent, "    case " . ucfirst($name) . "AttrNum: {\n");
774         push(@implContent, "        ExceptionCode ec = 0;\n");
775         push(@implContent, "        KJS::JSValue* result = " . NativeToJSValue($attribute->signature, "imp->$name(ec)") . ";\n");
776         push(@implContent, "        setDOMException(exec, ec);\n");
777         push(@implContent, "        return result;\n");
778         push(@implContent, "    }\n");
779       }
780     }
781
782     push(@implContent, "    }\n    return 0;\n}\n\n");
783     
784     # Check if we have any writable attributes
785     my $hasReadWriteProperties = 0;
786     foreach my $attribute (@{$dataNode->attributes}) {
787       $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
788     }
789     if ($hasReadWriteProperties) {
790       push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)\n");
791       if ($dataNode->extendedAttributes->{"HasCustomIndexSetter"}) {
792         push(@implContent, "{\n" .
793                            "    if (!lookupPut<$className>(exec, propertyName, value, attr, &${className}Table, this))\n");
794         push(@implContent, "        indexSetter(exec, propertyName, value, attr);\n");
795         push(@implContent, "}\n\n");
796       }
797       else {
798         push(@implContent, "{\n    lookupPut<$className, $parentClassName>" .
799                            "(exec, propertyName, value, attr, &${className}Table, this);\n}\n\n");
800       }
801
802       push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
803       push(@implContent, "{\n");
804       push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(impl());\n\n");
805       push(@implContent, "    switch (token) {\n");
806
807       foreach my $attribute (@{$dataNode->attributes}) {
808         if ($attribute->type !~ /^readonly/) {
809           my $name = $attribute->signature->name;
810  
811           if ($attribute->signature->extendedAttributes->{"Custom"}) {
812               push(@implContent, "    case " . ucfirst($name) . "AttrNum: {\n");
813               push(@implContent, "        set" . ucfirst($name) . "(exec, value);\n");
814           } elsif ($attribute->signature->type =~ /Constructor$/) {
815               my $constructorType = $attribute->signature->type;
816               $constructorType =~ s/Constructor$//;
817
818               $implIncludes{"JS" . $constructorType . ".h"} = 1;
819               push(@implContent, "    case " . $name ."ConstructorAttrNum: {\n");
820               push(@implContent, "        // Shadowing a built-in constructor\n");
821
822               # FIXME: We need to provide scalable hooks/attributes for this kind of extension
823               push(@implContent, "        if (isSafeScript(exec))\n");
824               push(@implContent, "            JSObject::put(exec, \"$name\", value);\n");
825           } else {
826               push(@implContent, "    case " . ucfirst($name) ."AttrNum: {\n");
827               push(@implContent, "        ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
828               push(@implContent, "        imp->set" . ucfirst($name) . "(" . JSValueToNative($attribute->signature, "value"));
829               push(@implContent, ", ec") if @{$attribute->setterExceptions};
830               push(@implContent, ");\n");
831               push(@implContent, "        setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
832           }
833           push(@implContent, "        break;\n");
834           push(@implContent, "    }\n");
835         }
836       }
837       push(@implContent, "    }\n"); # end switch
838         
839       if ($interfaceName eq "DOMWindow") {
840           push(@implContent, "    // FIXME: Hack to prevent unused variable warning -- remove once DOMWindow includes a settable property\n");
841           push(@implContent, "    (void)imp;\n");
842       }
843       push(@implContent, "}\n\n"); # end function
844     }
845   }
846
847   if ($dataNode->extendedAttributes->{"GenerateConstructor"}) {
848     push(@implContent, "JSValue* ${className}::getConstructor(ExecState* exec)\n{\n");
849     push(@implContent, "    return cacheGlobalObject<${className}Constructor>(exec, \"[[${interfaceName}.constructor]]\");\n");
850     push(@implContent, "}\n");
851   }    
852   
853   # Functions
854   if($numFunctions ne 0) {
855     push(@implContent, "JSValue* ${className}ProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)\n{\n");
856     push(@implContent, "    if (!thisObj->inherits(&${className}::info))\n");
857     push(@implContent, "      return throwError(exec, TypeError);\n\n");
858
859     push(@implContent, "    $implClassName* imp = static_cast<$implClassName*>(static_cast<$className*>(thisObj)->impl());\n\n");
860
861     push(@implContent, "    switch (id) {\n");
862     foreach my $function (@{$dataNode->functions}) {
863       push(@implContent, "    case ${className}::" . ucfirst($function->signature->name) . "FuncNum: {\n");
864
865       if ($function->signature->extendedAttributes->{"Custom"}) {
866         push(@implContent, "        return static_cast<${className}*>(thisObj)->" . $function->signature->name . "(exec, args);\n    }\n");
867         next;
868       }
869
870       AddIncludesForType($function->signature->type);
871
872       if (@{$function->raisesExceptions}) {
873         push(@implContent, "        ExceptionCode ec = 0;\n");
874       }
875
876       my $paramIndex = 0;
877       my $functionString = "imp->" . $function->signature->name . "(";
878       my $numParameters = @{$function->parameters};
879       my $hasOptionalArguments = 0;
880
881       # Special case for SVGLengthList / SVGTransformList / SVGPathSegList.
882       # These lists still use RefPtr objects, which will be changed in future.
883       # For now they need special treatment in the generation.
884       my $isRefPtr = 0;
885       if ($interfaceName eq "SVGLengthList" or
886           $interfaceName eq "SVGTransformList" or
887           $interfaceName eq "SVGPathSegList") {
888         $isRefPtr = 1;
889       }
890
891       foreach my $parameter (@{$function->parameters}) {
892         if (!$hasOptionalArguments && $parameter->extendedAttributes->{"Optional"}) {
893           push(@implContent, "\n        int argsCount = args.size();\n");
894           $hasOptionalArguments = 1;
895         }
896
897         if ($hasOptionalArguments) {
898           push(@implContent, "        if (argsCount < " . ($paramIndex + 1) . ") {\n");
899           GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    " x 3, $isRefPtr);
900           push(@implContent, "        }\n\n");
901         }
902
903         my $name = $parameter->name;
904         push(@implContent, "        bool ${name}Ok;\n") if TypeCanFailConversion($parameter);
905         push(@implContent, "        " . GetNativeType($parameter) . " $name = " . JSValueToNative($parameter, "args[$paramIndex]", TypeCanFailConversion($parameter) ? "${name}Ok" : undef) . ";\n");        
906         if (TypeCanFailConversion($parameter)) {
907           push(@implContent, "        if (!${name}Ok) {\n");
908           push(@implContent, "            setDOMException(exec, TYPE_MISMATCH_ERR);\n");
909           push(@implContent, "            return jsUndefined();\n        }\n");
910         }          
911
912         # If a parameter is "an index", it should throw an INDEX_SIZE_ERR
913         # exception        
914         if ($parameter->extendedAttributes->{"IsIndex"}) {
915           $implIncludes{"ExceptionCode.h"} = 1;
916           push(@implContent, "        if ($name < 0) {\n");
917           push(@implContent, "            setDOMException(exec, INDEX_SIZE_ERR);\n");
918           push(@implContent, "            return jsUndefined();\n        }\n");          
919         }
920
921         $functionString .= ", " if $paramIndex;
922         $functionString .= $name;
923
924         $paramIndex++;
925       }
926
927       push(@implContent, "\n");
928       GenerateImplementationFunctionCall($function, $functionString, $paramIndex, "    " x 2, $isRefPtr);
929
930       push(@implContent, "    }\n"); # end case
931     }
932     push(@implContent, "    }\n"); # end switch
933     push(@implContent, "    return 0;\n");
934     push(@implContent, "}\n");
935   }
936
937   if ($dataNode->extendedAttributes->{"HasIndexGetter"}) {
938     push(@implContent, "\nJSValue* ${className}::indexGetter(ExecState* exec, JSObject* originalObject, const Identifier& propertyName, const PropertySlot& slot)\n");
939     push(@implContent, "{\n");
940     push(@implContent, "    ${className}* thisObj = static_cast<$className*>(slot.slotBase());\n");
941     push(@implContent, "    return toJS(exec, static_cast<$implClassName*>(thisObj->impl())->item(slot.index()));\n");
942     push(@implContent, "}\n");
943   }
944
945   if (!$hasParent) {
946     my $implContent = << "EOF";
947 KJS::JSValue* toJS(KJS::ExecState* exec, $implClassName* obj)
948 {
949     return KJS::cacheDOMObject<$implClassName, $className>(exec, obj);
950 }
951 EOF
952     push(@implContent, $implContent);
953    }
954
955    if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) {
956     my $implContent = << "EOF";
957 $implClassName* to${interfaceName}(KJS::JSValue* val)
958 {
959     return val->isObject(&${className}::info) ? static_cast<$className*>(val)->impl() : 0;
960 }
961 EOF
962     push(@implContent, $implContent);
963   }
964   
965   if ($dataNode->extendedAttributes->{"GenerateNativeConverter"} && $hasParent) {
966     push(@implContent, "\n$implClassName* ${className}::impl() const\n");
967     push(@implContent, "{\n");
968     push(@implContent, "    return static_cast<$implClassName*>(${parentClassName}::impl());\n");
969     push(@implContent, "}\n");
970   }
971
972   push(@implContent, "\n}\n");
973     
974   push(@implContent, "\n#endif // ${conditional}_SUPPORT\n") if $conditional;
975 }
976
977 sub GenerateImplementationFunctionCall()
978 {
979     my $function = shift;
980     my $functionString = shift;
981     my $paramIndex = shift;
982     my $indent = shift;
983     my $isRefPtr = shift;
984
985     if (@{$function->raisesExceptions}) {
986         $functionString .= ", " if $paramIndex;
987         $functionString .= "ec";
988     }
989     $functionString .= ")";
990
991     if ($function->signature->type eq "void") {
992         push(@implContent, $indent . "$functionString;\n");
993         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
994         push(@implContent, $indent . "return jsUndefined();\n");
995     } else {
996         push(@implContent, "\n" . $indent . "KJS::JSValue* result = " . NativeToJSValue($function->signature, $functionString, $isRefPtr) . ";\n");
997         push(@implContent, $indent . "setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
998         push(@implContent, $indent . "return result;\n");
999     }
1000 }
1001
1002 sub GetNativeType
1003 {
1004     my $signature = shift;
1005     
1006     my $type = $codeGenerator->StripModule($signature->type);
1007     
1008     if ($type eq "boolean") {
1009         return "bool";
1010     } elsif ($type eq "unsigned long") {
1011         if ($signature->extendedAttributes->{"IsIndex"}) {
1012             # Special-case index arguments because we need to check that
1013             # they aren't < 0.        
1014             return "int";
1015         } else {
1016             return "unsigned";
1017         } 
1018     } elsif ($type eq "long") {
1019         return "int";
1020     } elsif ($type eq "unsigned short" or $type eq "float") {
1021         return $type;
1022     } elsif ($type eq "AtomicString") {
1023         return "AtomicString";
1024     } elsif ($type eq "DOMString") {
1025         return "String";
1026     } elsif ($type eq "NodeFilter") {
1027         return "PassRefPtr<${type}>";
1028     } elsif ($type eq "CompareHow") {
1029         return "Range::CompareHow";
1030     } elsif ($type eq "EventTarget") {
1031         return "EventTargetNode*";
1032     } elsif ($type eq "SVGRect") {
1033         return "FloatRect";
1034     } elsif ($type eq "SVGPoint") {
1035         return "FloatPoint";
1036     } elsif ($type eq "SVGNumber") {
1037         return "double";
1038     } elsif($type eq "SVGPaintType") {
1039         return "SVGPaint::SVGPaintType";
1040     }
1041
1042     # Default, assume native type is a pointer with same type name as idl type
1043     return "${type}*";
1044 }
1045
1046 sub TypeCanFailConversion
1047 {
1048   my $signature = shift;
1049   
1050   my $type = $codeGenerator->StripModule($signature->type);
1051
1052   if ($type eq "boolean") {
1053     return 0;
1054   } elsif ($type eq "unsigned long" or $type eq "long") {
1055     $implIncludes{"ExceptionCode.h"} = 1;
1056     return 1;
1057   } elsif ($type eq "unsigned short") {
1058     return 0; # or can it?
1059   } elsif ($type eq "CompareHow") {
1060     return 0; # or can it?
1061   } elsif ($type eq "float") {
1062     return 0;
1063   } elsif ($type eq "Attr") {
1064       $implIncludes{"ExceptionCode.h"} = 1;
1065       return 1;
1066   } elsif ($type eq "AtomicString" or
1067            $type eq "DOMString" or
1068            $type eq "Node" or
1069            $type eq "Element" or
1070            $type eq "DocumentType" or
1071            $type eq "EventTarget" or
1072            $type eq "Range" or
1073            $type eq "NodeFilter" or
1074            $type eq "DOMWindow" or
1075            $type eq "XPathEvaluator" or
1076            $type eq "XPathNSResolver" or
1077            $type eq "XPathResult" or
1078            $type eq "SVGAngle" or
1079            $type eq "SVGLength" or
1080            $type eq "SVGNumber" or
1081            $type eq "SVGPoint" or
1082            $type eq "SVGTransform" or
1083            $type eq "SVGPathSeg" or
1084            $type eq "SVGMatrix" or
1085            $type eq "SVGRect" or
1086            $type eq "SVGElement" or
1087            $type eq "HTMLOptionElement") {
1088       return 0;
1089   } elsif ($type eq "SVGPaintType") {
1090     return 0; # or can it?
1091   } else {
1092     die "Don't know whether a JS value can fail conversion to type $type."
1093   }
1094 }
1095
1096 sub JSValueToNative
1097 {
1098     my $signature = shift;
1099     my $value = shift;
1100     my $okParam = shift;
1101     my $maybeOkParam = $okParam ? ", ${okParam}" : "";
1102     
1103     my $type = $codeGenerator->StripModule($signature->type);
1104     
1105     if ($type eq "boolean") {
1106         return "$value->toBoolean(exec)";
1107     } elsif ($type eq "unsigned long" or
1108              $type eq "long" or
1109              $type eq "unsigned short") {
1110         if ($maybeOkParam) {
1111             return "$value->toInt32(exec${maybeOkParam})";
1112         } else {
1113             return "$value->toInt32(exec)";
1114         }
1115     } elsif ($type eq "CompareHow") {
1116         return "static_cast<Range::CompareHow>($value->toInt32(exec))";
1117     } elsif ($type eq "float") {
1118         return "$value->toNumber(exec)";
1119     } elsif ($type eq "AtomicString") {
1120         return "$value->toString(exec)";
1121     } elsif ($type eq "DOMString") {
1122         if ($signature->extendedAttributes->{"ConvertNullToNullString"}) {
1123             return "valueToStringWithNullCheck(exec, $value)";
1124         } else {
1125             return "$value->toString(exec)";
1126         }
1127     } elsif ($type eq "Node") {
1128         $implIncludes{"kjs_dom.h"} = 1;
1129         return "toNode($value)";
1130     } elsif ($type eq "EventTarget") {
1131         $implIncludes{"kjs_dom.h"} = 1;
1132         return "toEventTargetNode($value)";
1133     }  elsif ($type eq "Attr") {
1134         $implIncludes{"kjs_dom.h"} = 1;
1135         return "toAttr($value${maybeOkParam})";
1136     } elsif ($type eq "DocumentType") {
1137         $implIncludes{"kjs_dom.h"} = 1;
1138         return "toDocumentType($value)";
1139     } elsif ($type eq "Element") {
1140         $implIncludes{"kjs_dom.h"} = 1;
1141         return "toElement($value)";
1142     } elsif ($type eq "NodeFilter") {
1143         $implIncludes{"kjs_traversal.h"} = 1;
1144         return "toNodeFilter($value)";
1145     } elsif ($type eq "DOMWindow") {
1146         $implIncludes{"kjs_window.h"} = 1;
1147         return "toDOMWindow($value)";
1148     } elsif ($type eq "SVGRect") {
1149         $implIncludes{"JSSVGRect.h"} = 1;
1150         return "toFloatRect($value)";
1151     } elsif ($type eq "SVGPoint") {
1152         $implIncludes{"JSSVGPoint.h"} = 1;
1153         return "toFloatPoint($value)";
1154     } elsif ($type eq "SVGNumber") {
1155         return "$value->toNumber(exec)";
1156     } elsif ($type eq "SVGPaintType") {
1157         return "static_cast<SVGPaint::SVGPaintType>($value->toInt32(exec))";
1158     }
1159
1160     # Default, assume autogenerated type conversion routines
1161     $implIncludes{"JS$type.h"} = 1;
1162     return "to$type($value)";
1163 }
1164
1165 sub NativeToJSValue
1166 {
1167     my $signature = shift;
1168     my $value = shift;
1169     my $isRefPtr = shift;
1170  
1171     my $type = $codeGenerator->StripModule($signature->type);
1172
1173     if ($type eq "boolean") {
1174         return "jsBoolean($value)";
1175     } elsif ($type eq "long" or
1176              $type eq "unsigned long" or 
1177              $type eq "short" or 
1178              $type eq "unsigned short" or
1179              $type eq "float" or 
1180              $type eq "double") {
1181         return "jsNumber($value)";
1182     } elsif ($type eq "DOMString" or $type eq "AtomicString") {
1183         my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
1184         if (defined $conv) {
1185             if ($conv eq "Null") {
1186                 return "jsStringOrNull($value)";
1187             } elsif ($conv eq "Undefined") {
1188                 return "jsStringOrUndefined($value)";
1189             } elsif ($conv eq "False") {
1190                 return "jsStringOrFalse($value)";
1191             } else {
1192                 die "Unknown value for ConvertNullStringTo extended attribute";
1193             }
1194         } else {
1195             return "jsString($value)";
1196         }
1197     } elsif ($type eq "DOMImplementation") {
1198         $implIncludes{"kjs_dom.h"} = 1;
1199         $implIncludes{"JSDOMImplementation.h"} = 1;
1200         return "toJS(exec, $value)";
1201     } elsif ($type eq "Attr" or
1202              $type eq "CDATASection" or
1203              $type eq "Comment" or
1204              $type eq "Document" or
1205              $type eq "DocumentFragment" or
1206              $type eq "DocumentType" or
1207              $type eq "Element" or
1208              $type eq "EntityReference" or
1209              $type eq "HTMLDocument" or
1210              $type eq "Node" or
1211              $type eq "ProcessingInstruction" or
1212              $type eq "Text") {
1213         $implIncludes{"kjs_dom.h"} = 1;
1214         $implIncludes{"Comment.h"} = 1;
1215         $implIncludes{"CDATASection.h"} = 1;
1216         $implIncludes{"Node.h"} = 1;
1217         $implIncludes{"Element.h"} = 1;
1218         $implIncludes{"DocumentType.h"} = 1;
1219         return "toJS(exec, $value)";
1220     } elsif ($type eq "EventTarget") {
1221         $implIncludes{"kjs_dom.h"} = 1;
1222         $implIncludes{"EventTargetNode.h"} = 1;
1223         return "toJS(exec, $value)";
1224     } elsif ($type eq "Event") {
1225         $implIncludes{"kjs_events.h"} = 1;
1226         $implIncludes{"Event.h"} = 1;
1227         return "toJS(exec, $value)";
1228     } elsif ($type eq "NodeList" or $type eq "NamedNodeMap") {
1229         $implIncludes{"kjs_dom.h"} = 1;
1230         return "toJS(exec, $value)";
1231     } elsif ($type eq "CSSStyleSheet" or $type eq "StyleSheet" or $type eq "MediaList") {
1232         $implIncludes{"CSSStyleSheet.h"} = 1;
1233         $implIncludes{"MediaList.h"} = 1;
1234         $implIncludes{"kjs_css.h"} = 1;
1235         return "toJS(exec, $value)";
1236     } elsif ($type eq "StyleSheetList") {
1237         $implIncludes{"StyleSheetList.h"} = 1;
1238         $implIncludes{"kjs_css.h"} = 1;
1239         return "toJS(exec, $value, imp)";
1240     } elsif ($type eq "CSSStyleDeclaration" or $type eq "Rect") {
1241         $implIncludes{"CSSStyleDeclaration.h"} = 1;
1242         $implIncludes{"RectImpl.h"} = 1;
1243         $implIncludes{"kjs_css.h"} = 1;
1244         return "toJS(exec, $value)";
1245     } elsif ($type eq "RGBColor") {
1246         $implIncludes{"kjs_css.h"} = 1;
1247         return "getDOMRGBColor(exec, $value)";
1248     } elsif ($type eq "HTMLCanvasElement") {
1249         $implIncludes{"kjs_dom.h"} = 1;
1250         $implIncludes{"HTMLCanvasElement.h"} = 1;
1251         return "toJS(exec, $value)";
1252     } elsif ($type eq "DOMWindow") {
1253         $implIncludes{"kjs_window.h"} = 1;
1254         return "toJS(exec, $value)";
1255     } elsif ($type eq "DOMObject") {
1256         $implIncludes{"JSCanvasRenderingContext2D.h"} = 1;
1257         return "toJS(exec, $value)";
1258     } elsif ($type eq "HTMLFormElement") {
1259         $implIncludes{"kjs_html.h"} = 1;
1260         $implIncludes{"HTMLFormElement.h"} = 1;
1261         return "toJS(exec, $value)";
1262     } elsif ($type eq "HTMLCollection") {
1263         $implIncludes{"kjs_html.h"} = 1;
1264         $implIncludes{"HTMLCollection.h"} = 1;
1265         return "getHTMLCollection(exec, $value.get())";
1266     } elsif (($type eq "SVGLength" or
1267               $type eq "SVGTransform") and $isRefPtr eq 1) {
1268        $implIncludes{"JS$type.h"} = 1;
1269        $implIncludes{"$type.h"} = 1;
1270        return "toJS(exec, $value.get())";
1271     } elsif ($type eq "SVGRect" or
1272              $type eq "SVGPoint" or
1273              $type eq "SVGNumber") {
1274         $implIncludes{"JS$type.h"} = 1;
1275         return "getJS$type(exec, $value)";
1276     } elsif ($type =~ /SVGPathSeg/) {
1277         $implIncludes{"JS$type.h"} = 1;
1278         $joinedName = $type;
1279         $joinedName =~ s/Abs|Rel//;
1280         $implIncludes{"$joinedName.h"} = 1;
1281
1282         if ($isRefPtr eq 1) {
1283             return "toJS(exec, $value.get())";
1284         } else {
1285             return "toJS(exec, $value)";
1286         }
1287     } elsif ($codeGenerator->IsSVGAnimatedType($type)) {
1288         $implIncludes{"JS$type.h"} = 1;
1289         $implIncludes{"$type.h"} = 1;
1290         $tempValue = $value;
1291         $tempValue =~ s/\(\)//;
1292         $tempValue .= "Animated()";
1293         return "toJS(exec, $tempValue)";
1294     } elsif ($type eq "SVGPaintType") {
1295         return "jsNumber($value)";
1296     }
1297
1298     # Default, include header with same name.
1299     $implIncludes{"JS$type.h"} = 1;
1300     $implIncludes{"$type.h"} = 1;
1301     return "toJS(exec, $value)";
1302 }
1303
1304 # Internal Helper
1305 sub GenerateHashTable
1306 {
1307     my $object = shift;
1308     
1309     my $name = shift;
1310     my $size = shift;
1311     my $keys = shift;
1312     my $values = shift;
1313     my $specials = shift;
1314     my $parameters = shift;
1315     
1316     # Helpers
1317     my @table = ();
1318     my @links = ();
1319     
1320     my $maxDepth = 0;
1321     my $collisions = 0;
1322     my $numEntries = $size;
1323     
1324     # Collect hashtable information
1325     my $i = 0;
1326     foreach(@{$keys}) {
1327         my $depth = 0;
1328         my $h = $object->GenerateHashValue($_) % $numEntries;
1329         
1330         while(defined($table[$h])) {
1331             if (defined($links[$h])) {
1332                 $h = $links[$h];
1333                 $depth++;
1334             } else {
1335                 $collisions++;
1336                 $links[$h] = $size;
1337                 $h = $size;
1338                 $size++;
1339             }
1340         }
1341         
1342         $table[$h] = $i;
1343         
1344         $i++;
1345         $maxDepth = $depth if ($depth > $maxDepth);
1346     }
1347     
1348     # Ensure table is big enough (in case of undef entries at the end)
1349     if ($#table + 1 < $size) {
1350         $#table = $size - 1;
1351     }
1352     
1353     # Start outputing the hashtables
1354     my $nameEntries = "${name}Entries";
1355     $nameEntries =~ s/:/_/g;
1356     
1357     # first, build the string table
1358     my %soffset = ();
1359     if (($name =~ /Proto/) or ($name =~ /Constructor/)) {
1360         my $type = $name;
1361         my $implClass;
1362         
1363         if ($name =~ /Proto/) {
1364             $type =~ s/Proto.*//;
1365             $implClass = $type; $implClass =~ s/Wrapper$//;
1366             push(@implContent, "/* Hash table for prototype */\n");
1367         } else {
1368             $type =~ s/Constructor.*//;
1369             $implClass = $type; $implClass =~ s/Constructor$//;
1370             push(@implContent, "/* Hash table for constructor */\n");
1371         }
1372     } else {
1373         push(@implContent, "/* Hash table */\n");
1374     }
1375     
1376     # Dump the hash table
1377     push(@implContent, "\nstatic const HashEntry $nameEntries\[\] =\n\{\n");
1378     
1379     $i = 0;
1380     foreach $entry (@table) {
1381         if (defined($entry)) {
1382             my $key = @$keys[$entry];
1383             
1384             push(@implContent, "    \{ \"" . $key . "\"");
1385             push(@implContent, ", " . @$values[$entry]);
1386             push(@implContent, ", " . @$specials[$entry]);
1387             push(@implContent, ", " . @$parameters[$entry]);
1388             push(@implContent, ", ");
1389             
1390             if (defined($links[$i])) {
1391                 push(@implContent, "&${nameEntries}[$links[$i]]" . " \}");
1392             } else {
1393                 push(@implContent, "0 \}");
1394             }
1395         } else {
1396             push(@implContent, "    \{ 0, 0, 0, 0, 0 \}");
1397         }
1398         
1399         push(@implContent, ",") unless($i eq $size - 1);
1400         push(@implContent, "\n");
1401         
1402         $i++;
1403     }
1404     
1405     if ($size eq 0) {
1406         # dummy bucket -- an empty table would crash Lookup::findEntry
1407         push(@implContent, "    \{ 0, 0, 0, 0, 0 \}\n") ;
1408         $numEntries = 1;
1409         $size = 1;
1410     }
1411     push(@implContent, "};\n\n");
1412     push(@implContent, "static const HashTable $name = \n");
1413     push(@implContent, "{\n    2, $size, $nameEntries, $numEntries\n};\n\n");
1414 }
1415
1416 # Internal helper
1417 sub GenerateHashValue
1418 {
1419     my $object = shift;
1420     
1421     @chars = split(/ */, $_[0]);
1422     
1423     # This hash is designed to work on 16-bit chunks at a time. But since the normal case
1424     # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
1425     # were 16-bit chunks, which should give matching results
1426     
1427     my $EXP2_32 = 4294967296;
1428     
1429     my $hash = 0x9e3779b9;
1430     my $l    = scalar @chars; #I wish this was in Ruby --- Maks
1431     my $rem  = $l & 1;
1432     $l = $l >> 1;
1433     
1434     my $s = 0;
1435     
1436     # Main loop
1437     for (; $l > 0; $l--) {
1438         $hash   += ord($chars[$s]);
1439         my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
1440         $hash   = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
1441         $s += 2;
1442         $hash += $hash >> 11;
1443     }
1444     
1445     # Handle end case
1446     if ($rem !=0) {
1447         $hash += ord($chars[$s]);
1448         $hash ^= (leftShift($hash, 11)% $EXP2_32);
1449         $hash += $hash >> 17;
1450     }
1451     
1452     # Force "avalanching" of final 127 bits
1453     $hash ^= leftShift($hash, 3);
1454     $hash += ($hash >> 5);
1455     $hash = ($hash% $EXP2_32);
1456     $hash ^= (leftShift($hash, 2)% $EXP2_32);
1457     $hash += ($hash >> 15);
1458     $hash = $hash% $EXP2_32;
1459     $hash ^= (leftShift($hash, 10)% $EXP2_32);
1460     
1461     # this avoids ever returning a hash code of 0, since that is used to
1462     # signal "hash not computed yet", using a value that is likely to be
1463     # effectively the same as 0 when the low bits are masked
1464     $hash = 0x80000000  if ($hash == 0);
1465     
1466     return $hash;
1467 }
1468
1469 # Internal helper
1470 sub WriteData
1471 {
1472     if (defined($IMPL)) {
1473         # Write content to file.
1474         print $IMPL @implContentHeader;
1475         
1476         foreach my $implInclude (sort keys(%implIncludes)) {
1477             my $checkType = $implInclude;
1478             $checkType =~ s/\.h//;
1479     
1480             print $IMPL "#include \"$implInclude\"\n" unless($codeGenerator->IsSVGAnimatedType($checkType));
1481         }
1482         
1483         print $IMPL @implContent;
1484         close($IMPL);
1485         undef($IMPL);
1486         
1487         @implHeaderContent = "";
1488         @implContent = "";    
1489         %implIncludes = ();
1490     }
1491         
1492     if (defined($HEADER)) {
1493         # Write content to file.
1494         print $HEADER @headerContent;
1495         close($HEADER);
1496         undef($HEADER);
1497         
1498         @headerContent = "";
1499     }
1500 }
1501
1502 sub constructorFor
1503 {
1504     my $className = shift;
1505     my $protoClassName = shift;
1506     my $interfaceName = shift;
1507     my $canConstruct = shift;
1508     
1509 my $implContent = << "EOF";
1510 class ${className}Constructor : public DOMObject {
1511 public:
1512     ${className}Constructor(ExecState* exec) 
1513     { 
1514         setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); 
1515         putDirect(prototypePropertyName, ${protoClassName}::self(exec), None);
1516     }
1517     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
1518     JSValue* getValueProperty(ExecState*, int token) const;
1519     virtual const ClassInfo* classInfo() const { return &info; }
1520     static const ClassInfo info;
1521 EOF
1522
1523     if ($canConstruct) {
1524 $implContent .= << "EOF";
1525     virtual bool implementsConstruct() const { return true; }
1526     virtual JSObject* construct(ExecState* exec, const List& args) { return static_cast<JSObject*>(toJS(exec, new $interfaceName)); }
1527 EOF
1528     }
1529
1530 $implContent .= << "EOF";
1531 };
1532
1533 const ClassInfo ${className}Constructor::info = { "${interfaceName}Constructor", 0, &${className}ConstructorTable, 0 };
1534
1535 bool ${className}Constructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1536 {
1537     return getStaticValueSlot<${className}Constructor, DOMObject>(exec, &${className}ConstructorTable, this, propertyName, slot);
1538 }
1539
1540 JSValue* ${className}Constructor::getValueProperty(ExecState*, int token) const
1541 {
1542     // The token is the numeric value of its associated constant
1543     return jsNumber(token);
1544 }
1545
1546 EOF
1547
1548     return $implContent;
1549 }
1550
1551 sub protoFuncFor
1552 {
1553     my $className = shift;
1554     
1555 my $implContent = << "EOF";
1556 class ${className}ProtoFunc : public InternalFunctionImp {
1557 public:
1558     ${className}ProtoFunc(ExecState* exec, int i, int len, const Identifier& name)
1559     : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
1560     , id(i)
1561     {
1562         put(exec, lengthPropertyName, jsNumber(len), DontDelete|ReadOnly|DontEnum);
1563     }
1564     virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List& args);
1565 private:
1566     int id;
1567 };
1568
1569 EOF
1570   
1571     return $implContent;
1572 }
1573
1574 1;