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