LayoutTests:
[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 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 my %implIncludes = ();
33
34 # Default .h template
35 my $headerTemplate = << "EOF";
36 /*
37     This file is part of the KDE project.
38     This file has been generated by kdomidl.pl. DO NOT MODIFY!
39
40     This library is free software; you can redistribute it and/or
41     modify it under the terms of the GNU Library General Public
42     License as published by the Free Software Foundation; either
43     version 2 of the License, or (at your option) any later version.
44
45     This library is distributed in the hope that it will be useful,
46     but WITHOUT ANY WARRANTY; without even the implied warranty of
47     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
48     Library General Public License for more details.
49
50     You should have received a copy of the GNU Library General Public License
51     along with this library; see the file COPYING.LIB.  If not, write to
52     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
53     Boston, MA 02111-1307, USA.
54 */
55 EOF
56
57 # Default constructor
58 sub new
59 {
60   my $object = shift;
61   my $reference = { };
62
63   $codeGenerator = shift;
64   $outputDir = shift;
65
66   bless($reference, $object);
67   return $reference;
68 }
69
70 sub finish
71 {
72   my $object = shift;
73
74   # Commit changes!
75   $object->WriteData();
76 }
77
78 # Params: 'domClass' struct
79 sub GenerateInterface
80 {
81   my $object = shift;
82   my $dataNode = shift;
83
84   # FIXME: Check dates to see if we need to re-generate anything
85   
86   # Start actual generation..
87   $object->GenerateHeader($dataNode);
88   $object->GenerateImplementation($dataNode);
89
90   my $name = $dataNode->name;
91   
92   # Open files for writing...
93   my $headerFileName = "$outputDir/JS$name.h";
94   my $implFileName = "$outputDir/JS$name.cpp";
95
96   open($IMPL, ">$implFileName") || die "Couldn't open file $implFileName";
97   open($HEADER, ">$headerFileName") || die "Couldn't open file $headerFileName";
98 }
99
100 # Params: 'idlDocument' struct
101 sub GenerateModule
102 {
103   my $object = shift;
104   my $dataNode = shift;  
105   
106   $module = $dataNode->module;
107
108 }
109
110 sub GetParentClassName
111 {
112   my $dataNode = shift;
113   return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"};
114   return "KJS::DOMObject" if @{$dataNode->parents} eq 0;
115   return "JS" . $dataNode->parents(0);
116 }
117
118 sub GetLegacyHeaderIncludes
119 {
120   my $legacyParent = shift;
121   if ($legacyParent eq "JSCanvasRenderingContext2DBase") {
122     return "#include \"JSCanvasRenderingContext2DBase.h\"\n\n";
123   } elsif ($legacyParent eq "KJS::Window") {
124       return "#include \"kjs_window.h\"\n\n";
125   } elsif ($module eq "events") {
126     return "#include \"kjs_events.h\"\n\n";
127   } elsif ($module eq "core") {
128     return "#include \"kjs_dom.h\"\n\n";
129   } elsif ($module eq "css") {
130     return "#include \"kjs_css.h\"\n\n";
131   } elsif ($module eq "html") {
132     return "#include \"kjs_html.h\"\n\n";
133   } elsif ($module eq "traversal") {
134     return "#include \"kjs_traversal.h\"\n\n";
135   } else {
136     die ("Don't know what headers to include for module $module");
137   }
138 }
139
140 sub AddIncludesForType
141 {
142   my $type = shift;
143   
144   # When we're finished with the one-file-per-class 
145   # reorganization, we don't need these special cases.
146   
147   if ($type eq "Attr" or
148       $type eq "CDATASection" or
149       $type eq "CanvasPattern" or
150       $type eq "CharacterData" or
151       $type eq "Comment" or
152       $type eq "DOMException" or
153       $type eq "DOMImplementation" or
154       $type eq "DOMWindow" or
155       $type eq "Document" or
156       $type eq "DocumentFragment" or
157       $type eq "DocumentType" or 
158       $type eq "Element" or
159       $type eq "HTMLCanvasElement" or
160       $type eq "Node" or
161       $type eq "NodeList" or 
162       $type eq "Range" or 
163       $type eq "Text") {
164     $implIncludes{"${type}.h"} = 1;
165   } elsif ($type eq "CSSStyleSheet" or $type eq "StyleSheet") {
166     $implIncludes{"css_stylesheetimpl.h"} = 1;
167   } elsif ($type eq "CSSRuleList" or
168            $type eq "CSSRule") {
169     $implIncludes{"css_ruleimpl.h"} = 1;
170   } elsif ($type eq "CSSPrimitiveValue" or 
171            $type eq "CSSValue" or
172            $type eq "Counter" or 
173            $type eq "Rect" or 
174            $type eq "RGBColor") {
175     $implIncludes{"css_valueimpl.h"} = 1;
176   } elsif ($type eq "CSSStyleDeclaration") {
177     $implIncludes{"css_valueimpl.h"} = 1;
178   } elsif ($type eq "HTMLDocument") {
179     $implIncludes{"HTMLDocument.h"} = 1;
180   } elsif ($type eq "MutationEvent" or
181            $type eq "KeyboardEvent" or
182            $type eq "MouseEvent" or
183            $type eq "Event" or
184            $type eq "UIEvent" or
185            $type eq "WheelEvent") {
186     $implIncludes{"dom2_eventsimpl.h"} = 1;
187   } elsif ($type eq "NodeIterator" or
188            $type eq "NodeFilter" or
189            $type eq "TreeWalker") {
190     $implIncludes{"dom2_traversalimpl.h"} = 1;
191   } elsif ($type eq "ProcessingInstruction" or
192            $type eq "Entity" or
193            $type eq "EntityReference" or
194            $type eq "Notation") {
195     $implIncludes{"dom_xmlimpl.h"} = 1;
196   } elsif ($type eq "CanvasRenderingContext2D") {
197     $implIncludes{"CanvasGradient.h"} = 1;
198     $implIncludes{"CanvasPattern.h"} = 1;
199     $implIncludes{"CanvasRenderingContext2D.h"} = 1;
200     $implIncludes{"CanvasStyle.h"} = 1;
201   } elsif ($type eq "CanvasGradient") {
202     $implIncludes{"CanvasGradient.h"} = 1;
203     $implIncludes{"PlatformString.h"} = 1;
204   } elsif ($codeGenerator->IsPrimitiveType($type) or
205            $type eq "DOMString" or $type eq "DOMObject") {
206     # Do nothing
207   } else {
208     die "Don't know what to include for interface $type";
209   }
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   # FIXME: If we're sure that an interface can't have more than
222   # one parent we can do the check in the parser instead
223   if (@{$dataNode->parents} > 1) {
224     die "A class can't have more than one parent";
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   
232   # - Add default header template
233   @headerContent = split("\r", $headerTemplate);
234
235   # - Add header protection
236   push(@headerContent, "\n#ifndef $className" . "_H");
237   push(@headerContent, "\n#define $className" . "_H\n\n");
238   
239   if (exists $dataNode->extendedAttributes->{"LegacyParent"}) {
240     push(@headerContent, GetLegacyHeaderIncludes($dataNode->extendedAttributes->{"LegacyParent"}));
241   } else {
242     if ($hasParent) {
243       push(@headerContent, "#include \"$parentClassName.h\"\n");
244     } else {
245       push(@headerContent, "#include \"kjs_binding.h\"\n");
246     }
247   }
248   
249   my $numAttributes = @{$dataNode->attributes};
250   my $numFunctions = @{$dataNode->functions};
251   my $numConstants = @{$dataNode->constants};
252   
253   push(@headerContent, "\nnamespace WebCore {\n\n");
254   
255   # Implementation class forward declaration
256   push(@headerContent, "class $implClassName;\n\n");
257
258   # Class declaration
259   push(@headerContent, "class $className : public $parentClassName {\n");
260   push(@headerContent, "public:\n");
261   
262   # Constructor
263   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
264       push(@headerContent, "    $className($implClassName*);\n");
265   } else {
266       push(@headerContent, "    $className(KJS::ExecState*, $implClassName*);\n");
267   }
268     
269   # Destructor
270   if (!$hasParent or $interfaceName eq "Document") {
271     push(@headerContent, "    virtual ~$className();\n");
272   }
273   
274   # Getters
275   if ($numAttributes > 0) {
276     push(@headerContent, "    virtual bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
277     push(@headerContent, "    KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
278   }
279   
280   # Check if we have any writable properties
281   my $hasReadWriteProperties = 0;
282   foreach(@{$dataNode->attributes}) {
283     if($_->type !~ /^readonly\ attribute$/) {
284       $hasReadWriteProperties = 1;
285     }
286   }
287   
288   if ($hasReadWriteProperties) {
289     push(@headerContent, "    virtual void put(KJS::ExecState*, const KJS::Identifier&, KJS::JSValue*, int attr = KJS::None);\n");
290     push(@headerContent, "    void putValueProperty(KJS::ExecState*, int, KJS::JSValue*, int attr);\n");
291   }
292   
293   # Class info
294   push(@headerContent, "    virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
295   push(@headerContent, "    static const KJS::ClassInfo info;\n");
296   
297   # Constructor object getter
298   if ($numConstants ne 0) {
299     push(@headerContent, "    static KJS::JSValue* getConstructor(KJS::ExecState*);\n")
300   }
301
302   # Attribute and function enums
303   if ($numAttributes + $numFunctions > 0) {
304     push(@headerContent, "    enum {\n")
305   }
306   
307   if ($numAttributes > 0) {
308     push(@headerContent, "        // Attributes\n        ");
309     
310     my $i = -1;
311     foreach(@{$dataNode->attributes}) {
312       my $attribute = $_;
313
314       $i++;
315       if((($i % 4) eq 0) and ($i ne 0)) {
316         push(@headerContent, "\n        ");
317       }
318
319       my $value = ucfirst($attribute->signature->name) . "AttrNum";
320       $value .= ", " if(($i < $numAttributes - 1));
321       $value .= ", " if(($i eq $numAttributes - 1) and ($numFunctions ne 0));
322       push(@headerContent, $value);
323     }
324   }
325   
326   if ($numFunctions > 0) {
327     if ($numAttributes > 0) {
328       push(@headerContent, "\n\n");
329     }
330     push(@headerContent,"        // Functions\n        ");
331
332     $i = -1;
333     foreach(@{$dataNode->functions}) {
334       my $function = $_;
335
336       $i++;
337       if ((($i % 4) eq 0) and ($i ne 0)) {
338         push(@headerContent, "\n        ");
339       }
340
341       my $value = ucfirst($function->signature->name) . "FuncNum";
342       $value .= ", " if ($i < $numFunctions - 1);
343       push(@headerContent, $value);
344     }
345   }
346   
347   if ($numAttributes + $numFunctions > 0) {
348     push(@headerContent, "\n    };\n");
349   }
350
351   if (!$hasParent) {
352     push(@headerContent, "    $implClassName* impl() const { return m_impl.get(); }\n");
353     push(@headerContent, "private:\n");
354     push(@headerContent, "    RefPtr<$implClassName> m_impl;\n");
355   }
356   
357   push(@headerContent, "};\n\n");
358   
359   if (!$hasParent) {
360     push(@headerContent, "KJS::JSValue* toJS(KJS::ExecState*, $implClassName*);\n");
361     push(@headerContent, "$implClassName* to${interfaceName}(KJS::JSValue*);\n\n");
362   }
363
364   # Add prototype declaration -- code adopted from the KJS_DEFINE_PROTOTYPE and KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE macros
365   if ($numFunctions > 0 || $numConstants > 0) {
366       push(@headerContent, "class ${className}Proto : public KJS::JSObject {\n");
367       if (!$dataNode->extendedAttributes->{"DoNotCache"}) {
368           push(@headerContent, "    friend KJS::JSObject* KJS_GCC_ROOT_NS_HACK cacheGlobalObject<${className}Proto>(KJS::ExecState*, const KJS::Identifier& propertyName);\n");
369       }
370       push(@headerContent, "public:\n");
371       if ($dataNode->extendedAttributes->{"DoNotCache"}) {
372           push(@headerContent, "    static KJS::JSObject* self();\n");
373       } else {
374           push(@headerContent, "    static KJS::JSObject* self(KJS::ExecState* exec);\n");
375       }
376       push(@headerContent, "    virtual const KJS::ClassInfo* classInfo() const { return &info; }\n");
377       push(@headerContent, "    static const KJS::ClassInfo info;\n");
378       push(@headerContent, "    bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&);\n");
379       if ($numConstants ne 0) {
380           push(@headerContent, "    KJS::JSValue* getValueProperty(KJS::ExecState*, int token) const;\n");
381       }
382       push(@headerContent, "protected:\n");
383       if ($dataNode->extendedAttributes->{"DoNotCache"}) {
384           push(@headerContent, "    ${className}Proto() { }\n");
385       } else {
386           push(@headerContent, "    ${className}Proto(KJS::ExecState* exec)\n");
387           if ($hasParent && $parentClassName ne "KJS::DOMCSSRule" && $parentClassName ne "KJS::DOMNodeFilter") {
388               push(@headerContent, "        : KJS::JSObject(${parentClassName}Proto::self(exec)) { }\n");
389           } else {
390               push(@headerContent, "        : KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { }\n");
391           }
392       }
393       push(@headerContent, "};\n\n");
394   }
395   
396   push(@headerContent, "}\n\n#endif\n");
397 }
398
399 sub GenerateImplementation
400 {
401   my $object = shift;
402   my $dataNode = shift;
403   
404   my $interfaceName = $dataNode->name;
405   my $className = "JS$interfaceName";
406   my $implClassName = $interfaceName;
407   
408   my $hasLegacyParent = $dataNode->extendedAttributes->{"LegacyParent"};
409   my $hasRealParent = @{$dataNode->parents} > 0;
410   my $hasParent = $hasLegacyParent || $hasRealParent;
411   my $parentClassName = GetParentClassName($dataNode);
412   
413   # - Add default header template
414   @implContentHeader = split("\r", $headerTemplate);
415   push(@implContentHeader, "\n");
416   push(@implContentHeader,, "#include \"config.h\"\n");
417   push(@implContentHeader, "#include \"$className.h\"\n\n");
418
419
420   AddIncludesForType($interfaceName);
421
422   @implContent = ();
423
424   push(@implContent, "\nusing namespace KJS;\n\n");  
425   push(@implContent, "namespace WebCore {\n\n");
426   
427   # - Add all attributes in a hashtable definition
428   my $numAttributes = @{$dataNode->attributes};
429   if ($numAttributes > 0) {
430     my $hashSize = $numAttributes;
431     my $hashName = $className . "Table";
432
433     my @hashKeys = ();      # ie. 'insertBefore'
434     my @hashValues = ();    # ie. 'JSNode::InsertBefore'
435     my @hashSpecials = ();    # ie. 'DontDelete|Function'
436     my @hashParameters = ();  # ie. '2'
437
438     foreach my $attribute (@{$dataNode->attributes}) {
439       my $name = $attribute->signature->name;
440       push(@hashKeys, $name);
441       
442       my $value = $className . "::" . ucfirst($name) . "AttrNum";
443       push(@hashValues, $value);
444
445       my $special = "DontDelete";
446       $special .= "|ReadOnly" if($attribute->type =~ /readonly/);
447       push(@hashSpecials, $special);
448
449       my $numParameters = "0";
450       push(@hashParameters, $numParameters);      
451     }
452
453     $object->GenerateHashTable($hashName, $hashSize,
454                             \@hashKeys, \@hashValues,
455                              \@hashSpecials, \@hashParameters);
456   }
457   
458   # - Add all constants
459   my $numConstants = @{$dataNode->constants};
460   if ($numConstants ne 0) {
461     $hashSize = $numConstants;
462     $hashName = $className . "ConstructorTable";
463
464     @hashKeys = ();
465     @hashValues = ();
466     @hashSpecials = ();
467     @hashParameters = ();
468     
469     foreach my $constant (@{$dataNode->constants}) {
470       my $name = $constant->name;
471       push(@hashKeys, $name);
472      
473       my $value = "${implClassName}::$name";
474       push(@hashValues, $value);
475
476       my $special = "DontDelete|ReadOnly";
477       push(@hashSpecials, $special);
478
479       my $numParameters = 0;
480       push(@hashParameters, $numParameters); 
481     }
482     
483     $object->GenerateHashTable($hashName, $hashSize,
484                                \@hashKeys, \@hashValues,
485                                \@hashSpecials, \@hashParameters);
486                                
487     push(@implContent, constructorFor($className, $interfaceName));
488   }
489   
490   # - Add functions and constants to a hashtable definition
491   my $numFunctions = @{$dataNode->functions};
492   if ($numFunctions > 0 || $numConstants > 0) {
493     $hashSize = $numFunctions + $numConstants;
494     $hashName = $className . "ProtoTable";
495
496     @hashKeys = ();
497     @hashValues = ();
498     @hashSpecials = ();
499     @hashParameters = ();
500
501     foreach my $constant (@{$dataNode->constants}) {
502         my $name = $constant->name;
503         push(@hashKeys, $name);
504         
505         my $value = "${implClassName}::$name";
506         push(@hashValues, $value);
507         
508         my $special = "DontDelete|ReadOnly";
509         push(@hashSpecials, $special);
510         
511         my $numParameters = 0;
512         push(@hashParameters, $numParameters); 
513     }
514     
515     foreach my $function (@{$dataNode->functions}) {
516       my $name = $function->signature->name;
517       push(@hashKeys, $name);
518     
519       my $value = $className . "::" . ucfirst($name) . "FuncNum";
520       push(@hashValues, $value);
521     
522       my $special = "DontDelete|Function";
523       push(@hashSpecials, $special);
524     
525       my $numParameters = @{$function->parameters};
526       push(@hashParameters, $numParameters);
527     }
528     
529     $object->GenerateHashTable($hashName, $hashSize,
530                                \@hashKeys, \@hashValues,
531                                \@hashSpecials, \@hashParameters);
532
533     if($numFunctions > 0) {
534         push(@implContent, protoFuncFor($className));
535     }
536
537     push(@implContent, "const ClassInfo ${className}Proto::info = { \"$interfaceName\", 0, &${className}ProtoTable, 0 };\n\n");
538     if ($dataNode->extendedAttributes->{"DoNotCache"}) {
539         push(@implContent, "JSObject* ${className}Proto::self()\n");
540         push(@implContent, "{\n");
541         push(@implContent, "    return new ${className}Proto();\n");
542         push(@implContent, "}\n\n");
543     } else {
544         push(@implContent, "JSObject* ${className}Proto::self(ExecState* exec)\n");
545         push(@implContent, "{\n");
546         push(@implContent, "    return ::cacheGlobalObject<${className}Proto>(exec, \"[[${className}.prototype]]\");\n");
547         push(@implContent, "}\n\n");
548     }
549     push(@implContent, "bool ${className}Proto::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
550     push(@implContent, "{\n");
551     if ($numConstants eq 0) {
552         push(@implContent, "    return getStaticFunctionSlot<${className}ProtoFunc, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
553     } elsif ($numFunctions eq 0) {
554         push(@implContent, "    return getStaticValueSlot<${className}Proto, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
555     } else {
556         push(@implContent, "    return getStaticPropertySlot<${className}ProtoFunc, ${className}Proto, JSObject>(exec, &${className}ProtoTable, this, propertyName, slot);\n");
557     }
558     push(@implContent, "}\n\n");
559     if ($numConstants ne 0) {
560         push(@implContent, "JSValue* ${className}Proto::getValueProperty(ExecState*, int token) const\n{\n");
561         push(@implContent, "    // The token is the numeric value of its associated constant\n");
562         push(@implContent, "    return jsNumber(token);\n}\n\n");
563     }
564   }
565   
566   # - Initialize static ClassInfo object
567   push(@implContent, "const ClassInfo $className" . "::info = { \"$interfaceName\", ");
568   if ($hasParent) {
569     push(@implContent, "&" .$parentClassName . "::info, ");
570   } else {
571     push(@implContent, "0, ");
572   }
573   
574   if ($numAttributes > 0) {
575     push(@implContent, "&${className}Table, ");
576   } else {
577     push(@implContent, "0, ")
578   }
579   push(@implContent, "0 };\n\n");
580     
581   # Constructor
582   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
583       push(@implContent, "${className}::$className($implClassName* impl)\n");
584       push(@implContent, "    : $parentClassName(impl)\n");
585   } else {
586       push(@implContent, "${className}::$className(ExecState* exec, $implClassName* impl)\n");
587       if ($hasParent) {
588           push(@implContent, "    : $parentClassName(exec, impl)\n");
589       } else {
590           push(@implContent, "    : m_impl(impl)\n");
591       }
592   }
593   
594   if ($dataNode->extendedAttributes->{"DoNotCache"}) {
595       push(@implContent, "{\n    setPrototype(${className}Proto::self());\n}\n\n");
596   } elsif ($numFunctions ne 0 || $numConstants ne 0) {
597       push(@implContent, "{\n    setPrototype(${className}Proto::self(exec));\n}\n\n");
598   } else {
599       push(@implContent, "{\n}\n\n");    
600   }
601   
602   # Destructor
603   if (!$hasParent) {
604     push(@implContent, "${className}::~$className()\n");
605     push(@implContent, "{\n    ScriptInterpreter::forgetDOMObject(m_impl.get());\n}\n\n");    
606   }
607
608   # Document needs a special destructor because it's a special case for caching. It needs
609   # its own special handling rather than relying on the caching that Node normally does.
610   if ($interfaceName eq "Document") {
611     push(@implContent, "${className}::~$className()\n");
612     push(@implContent, "{\n    ScriptInterpreter::forgetDOMObject(static_cast<${implClassName}*>(m_impl.get()));\n}\n\n");    
613   }
614   
615   # Attributes
616   if ($numAttributes ne 0) {
617     push(@implContent, "bool ${className}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n");
618     push(@implContent, "{\n");
619     push(@implContent, "    return getStaticValueSlot<$className, $parentClassName>(exec, &${className}Table, this, propertyName, slot);\n");
620     push(@implContent, "}\n\n");
621   
622     push(@implContent, "JSValue* ${className}::getValueProperty(ExecState *exec, int token) const\n{\n");
623     push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(${className}::impl());\n\n");
624     push(@implContent, "    switch (token) {\n");
625
626     foreach my $attribute (@{$dataNode->attributes}) {
627       my $name = $attribute->signature->name;
628   
629       if (!@{$attribute->getterExceptions}) {
630         push(@implContent, "    case " . ucfirst($name) . "AttrNum:\n");
631         push(@implContent, "        return " . NativeToJSValue($attribute->signature, "impl->$name()") . ";\n");
632       } else {
633         push(@implContent, "    case " . ucfirst($name) . "AttrNum: {\n");
634         push(@implContent, "        ExceptionCode ec = 0;\n");
635         push(@implContent, "        KJS::JSValue* result = " . NativeToJSValue($attribute->signature, "impl->$name(ec)") . ";\n");
636         push(@implContent, "        setDOMException(exec, ec);\n");
637         push(@implContent, "        return result;\n");
638         push(@implContent, "    }\n");
639       }
640     }
641
642     push(@implContent, "    }\n    return 0;\n}\n\n");
643     
644     # Check if we have any writable attributes
645     my $hasReadWriteProperties = 0;
646     foreach my $attribute (@{$dataNode->attributes}) {
647       $hasReadWriteProperties = 1 if $attribute->type !~ /^readonly/;
648     }
649     if ($hasReadWriteProperties) {
650       push(@implContent, "void ${className}::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)\n");
651       push(@implContent, "{\n    lookupPut<$className, $parentClassName>" .
652                          "(exec, propertyName, value, attr, &${className}Table, this);\n}\n\n");
653                          
654       push(@implContent, "void ${className}::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)\n");
655       push(@implContent, "{\n");
656       push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(${className}::impl());\n\n");
657       push(@implContent, "    switch (token) {\n");
658       
659       foreach my $attribute (@{$dataNode->attributes}) {
660         if ($attribute->type !~ /^readonly/) {
661           my $name = $attribute->signature->name;
662           push(@implContent, "    case " . ucfirst($name) ."AttrNum: {\n");
663           push(@implContent, "        ExceptionCode ec = 0;\n") if @{$attribute->setterExceptions};
664           push(@implContent, "        impl->set" . ucfirst($name) . "(" . JSValueToNative($attribute->signature, "value"));
665           push(@implContent, ", ec") if @{$attribute->setterExceptions};
666           push(@implContent, ");\n");
667           push(@implContent, "        setDOMException(exec, ec);\n") if @{$attribute->setterExceptions};
668           push(@implContent, "    }\n");
669           push(@implContent, "        break;\n");
670         }
671       }
672       push(@implContent, "    }\n}\n\n");      
673     }
674   }
675
676   if ($numConstants ne 0) {
677     push(@implContent, "JSValue* ${className}::getConstructor(ExecState* exec)\n{\n");
678     push(@implContent, "    return cacheGlobalObject<${className}Constructor>(exec, \"[[${interfaceName}.constructor]]\");\n");
679     push(@implContent, "}\n");
680   }    
681   
682   # Functions
683   if($numFunctions ne 0) {
684     push(@implContent, "JSValue* ${className}ProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)\n{\n");
685     push(@implContent, "    if (!thisObj->inherits(&${className}::info))\n");
686     push(@implContent, "      return throwError(exec, TypeError);\n\n");
687
688     push(@implContent, "    $implClassName* impl = static_cast<$implClassName*>(static_cast<$className*>(thisObj)->impl());\n\n");
689     
690     
691     push(@implContent, "    switch (id) {\n");
692     foreach my $function (@{$dataNode->functions}) {      
693       push(@implContent, "    case ${className}::" . ucfirst($function->signature->name) . "FuncNum: {\n");
694       
695       AddIncludesForType($function->signature->type);
696       
697       my $paramIndex = 0;
698       my $functionString = "impl->" . $function->signature->name . "(";
699       my $numParameters = @{$function->parameters};
700       
701       foreach my $parameter (@{$function->parameters}) {
702         my $name = $parameter->name;
703         push(@implContent, "        bool ${name}Ok;\n") if TypeCanFailConversion($parameter);
704         push(@implContent, "        " . GetNativeType($parameter) . " $name = " . JSValueToNative($parameter, "args[$paramIndex]", TypeCanFailConversion($parameter) ? "${name}Ok" : undef) . ";\n");        
705         if (TypeCanFailConversion($parameter)) {
706             push(@implContent, "        if (!${name}Ok) {\n");
707             push(@implContent, "            setDOMException(exec, TYPE_MISMATCH_ERR);\n");
708             push(@implContent, "            return jsUndefined();\n        }\n");
709         }          
710         
711         # If a parameter is "an index", it should throw an INDEX_SIZE_ERR
712         # exception        
713         if ($parameter->extendedAttributes->{"IsIndex"}) {
714           $implIncludes{"ExceptionCode.h"} = 1;
715           push(@implContent, "        if ($name < 0) {\n");
716           push(@implContent, "            setDOMException(exec, INDEX_SIZE_ERR);\n");
717           push(@implContent, "            return jsUndefined();\n        }\n");          
718         }
719         
720         $functionString .= ", " if $paramIndex;
721         $functionString .= $name;
722
723         $paramIndex++;
724       }
725   
726       if (@{$function->raisesExceptions}) {
727         $functionString .= ", " if $paramIndex;
728         $functionString .= "ec";
729         push(@implContent, "        ExceptionCode ec = 0;\n");
730       }
731       $functionString .= ")";
732       
733       if ($function->signature->type eq "void") {
734         push(@implContent, "\n        $functionString;\n");
735         push(@implContent, "        setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
736         push(@implContent, "        return jsUndefined();\n");
737       } else {
738         push(@implContent, "\n        KJS::JSValue* result = " . NativeToJSValue($function->signature, $functionString) . ";\n");
739         push(@implContent, "        setDOMException(exec, ec);\n") if @{$function->raisesExceptions};
740         push(@implContent, "        return result;\n");
741       }
742
743       push(@implContent, "    }\n");
744     }
745     push(@implContent, "    }\n");
746     push(@implContent, "    return 0;\n");
747     push(@implContent, "}\n")
748   }
749   
750   if (!$hasParent) {
751     push(@implContent, toFunctionsFor($className, $implClassName, $interfaceName));
752   }
753
754   push(@implContent, "\n}\n");
755 }
756
757 sub GetNativeType
758 {
759   my $signature = shift;
760   
761   my $type = $signature->type;
762   
763   if ($type eq "boolean") {
764     return "bool";
765   } elsif ($type eq "unsigned long") {
766     if ($signature->extendedAttributes->{"IsIndex"}) {
767       # Special-case index arguments because we need to check that
768       # they aren't < 0.        
769       return "int";
770     } else {
771       return "unsigned";
772     } 
773   } elsif ($type eq "long") {
774     return "int";
775   } elsif ($type eq "unsigned short") {
776     return "unsigned short";
777   } elsif ($type eq "float") {
778     return "float";
779   } elsif ($type eq "AtomicString") {
780     return "AtomicString";
781   } elsif ($type eq "DOMString") {
782     return "String";
783   } elsif ($type eq "Node" or
784            $type eq "Element" or
785            $type eq "Attr" or
786            $type eq "DocumentType" or
787            $type eq "Range") {
788     return "${type}*";
789   } elsif ($type eq "NodeFilter") {
790       return "PassRefPtr<${type}>";
791   } elsif ($type eq "CompareHow") {
792     return "Range::CompareHow";
793   } elsif ($type eq "EventTarget") {
794     return "EventTargetNode*";
795   } elsif ($type eq "DOMWindow") {
796     return "DOMWindow*";
797   } else {
798     die "Don't know the native type of $type";
799   }
800 }
801
802 sub TypeCanFailConversion
803 {
804   my $signature = shift;
805   
806   my $type = $signature->type;
807
808   if ($type eq "boolean") {
809     return 0;
810   } elsif ($type eq "unsigned long" or $type eq "long") {
811     return 0; # or can it?
812   } elsif ($type eq "unsigned short") {
813     return 0; # or can it?
814   } elsif ($type eq "CompareHow") {
815     return 0; # or can it?
816   } elsif ($type eq "float") {
817     return 0;
818   } elsif ($type eq "AtomicString") {
819       return 0;
820   } elsif ($type eq "DOMString") {
821       return 0;
822   } elsif ($type eq "Node") {
823       return 0;
824   } elsif ($type eq "Element") {
825       return 0;
826   } elsif ($type eq "Attr") {
827       $implIncludes{"ExceptionCode.h"} = 1;
828       return 1;
829   } elsif ($type eq "DocumentType") {
830       return 0;
831   } elsif ($type eq "EventTarget") {
832       return 0;
833   }  elsif ($type eq "Range") {
834       return 0;
835   }  elsif ($type eq "NodeFilter") {
836       return 0;
837   } elsif ($type eq "DOMWindow") {
838       return 0;
839   } else {
840     die "Don't know whether a JS value can fail conversion to type $type."
841   }
842 }
843
844 sub JSValueToNative
845 {
846   my $signature = shift;
847   my $value = shift;
848   my $okParam = shift;
849   my $maybeOkParam = $okParam ? ", ${okParam}" : "";
850   
851   my $type = $signature->type;
852
853   if ($type eq "boolean") {
854     my $conv = $signature->extendedAttributes->{"ConvertUndefinedToTrue"};
855     if (defined $conv) {
856         return "valueToBooleanTreatUndefinedAsTrue(exec, $value)";
857     } else {
858         return "$value->toBoolean(exec)";
859     }
860   } elsif ($type eq "unsigned long" or $type eq "long") {
861     return "$value->toInt32(exec)";
862   } elsif ($type eq "unsigned short") {
863     return "$value->toInt32(exec)";
864   } elsif ($type eq "CompareHow") {
865     return "static_cast<Range::CompareHow>($value->toInt32(exec))";
866   } elsif ($type eq "float") {
867     return "$value->toNumber(exec)";
868   } elsif ($type eq "AtomicString") {
869     return "$value->toString(exec)";
870   } elsif ($type eq "DOMString") {
871     if ($signature->extendedAttributes->{"ConvertNullToNullString"}) {
872       return "valueToStringWithNullCheck(exec, $value)";
873     } else {
874       return "$value->toString(exec)";
875     }
876   } elsif ($type eq "Node") {
877     $implIncludes{"kjs_dom.h"} = 1;
878     return "toNode($value)";
879   } elsif ($type eq "EventTarget") {
880     $implIncludes{"kjs_dom.h"} = 1;
881     return "toEventTargetNode($value)";
882   }  elsif ($type eq "Attr") {
883     $implIncludes{"kjs_dom.h"} = 1;
884     return "toAttr($value${maybeOkParam})";
885   } elsif ($type eq "DocumentType") {
886       $implIncludes{"kjs_dom.h"} = 1;
887       return "toDocumentType($value)";
888   } elsif ($type eq "Range") {
889       $implIncludes{"JSRange.h"} = 1;
890       return "toRange($value)";
891   } elsif ($type eq "Element") {
892     $implIncludes{"kjs_dom.h"} = 1;
893     return "toElement($value)";
894   } elsif ($type eq "NodeFilter") {
895     $implIncludes{"kjs_traversal.h"} = 1;
896     return "toNodeFilter($value)";
897   } elsif ($type eq "DOMWindow") {
898     $implIncludes{"kjs_window.h"} = 1;
899     return "toDOMWindow($value)";
900   } else {
901     die "Don't know how to convert a JS value of type $type."
902   }
903 }
904
905 sub NativeToJSValue
906 {
907   my $signature = shift;
908   my $value = shift;
909   
910   my $type = $signature->type;
911   
912   if ($type eq "boolean") {
913     return "jsBoolean($value)";
914   } elsif ($type eq "long" or
915            $type eq "unsigned long" or 
916            $type eq "short" or 
917            $type eq "unsigned short" or
918            $type eq "float") {
919     return "jsNumber($value)";
920   } elsif ($type eq "DOMString") {
921     my $conv = $signature->extendedAttributes->{"ConvertNullStringTo"};
922     if (defined $conv) {
923       if ($conv eq "Null") {
924         return "jsStringOrNull($value)";
925       } elsif ($conv eq "Undefined") {
926         return "jsStringOrUndefined($value)";
927       } elsif ($conv eq "False") {
928         return "jsStringOrFalse($value)";
929       } else {
930         die "Unknown value for ConvertNullStringTo extended attribute";
931       }
932     } else {
933       return "jsString($value)";
934     }
935   } elsif ($type eq "DOMImplementation") {
936     $implIncludes{"kjs_dom.h"} = 1;
937     $implIncludes{"JSDOMImplementation.h"} = 1;
938     return "toJS(exec, $value)";
939   } elsif ($type eq "Attr" or
940            $type eq "CDATASection" or
941            $type eq "Comment" or
942            $type eq "Document" or
943            $type eq "DocumentFragment" or
944            $type eq "DocumentType" or
945            $type eq "Element" or
946            $type eq "EntityReference" or
947            $type eq "HTMLDocument" or
948            $type eq "Node" or
949            $type eq "ProcessingInstruction" or
950            $type eq "Text") {
951     $implIncludes{"kjs_dom.h"} = 1;
952     $implIncludes{"Comment.h"} = 1;
953     $implIncludes{"CDATASection.h"} = 1;
954     $implIncludes{"Node.h"} = 1;
955     $implIncludes{"Element.h"} = 1;
956     $implIncludes{"DocumentType.h"} = 1;
957     return "toJS(exec, $value)";
958   } elsif ($type eq "EventTarget") {
959     $implIncludes{"kjs_dom.h"} = 1;
960     $implIncludes{"EventTargetNode.h"} = 1;
961     return "toJS(exec, $value)";
962   } elsif ($type eq "Event") {
963     $implIncludes{"kjs_events.h"} = 1;
964     $implIncludes{"dom2_eventsimpl.h"} = 1;
965     return "toJS(exec, $value)";
966   } elsif ($type eq "NodeList" or $type eq "NamedNodeMap") {
967     $implIncludes{"kjs_dom.h"} = 1;
968     return "toJS(exec, $value)";
969   } elsif ($type eq "CSSStyleSheet" or $type eq "StyleSheet" or $type eq "MediaList") {
970     $implIncludes{"css_stylesheetimpl.h"} = 1;
971     $implIncludes{"css_ruleimpl.h"} = 1;
972     $implIncludes{"kjs_css.h"} = 1;
973     return "toJS(exec, $value)";    
974   } elsif ($type eq "StyleSheetList") {
975     $implIncludes{"css_stylesheetimpl.h"} = 1;
976     $implIncludes{"kjs_css.h"} = 1;
977     return "toJS(exec, $value, impl)";    
978   } elsif ($type eq "CSSRuleList") {
979     $implIncludes{"css_ruleimpl.h"} = 1;
980     return "toJS(exec, $value)";  
981   } elsif ($type eq "CSSStyleDeclaration" or $type eq "Rect") {
982     $implIncludes{"css_valueimpl.h"} = 1;
983     $implIncludes{"kjs_css.h"} = 1;
984     return "toJS(exec, $value)";
985   } elsif ($type eq "RGBColor") {
986     $implIncludes{"kjs_css.h"} = 1;
987     return "getDOMRGBColor(exec, $value)";
988   } elsif ($type eq "HTMLCanvasElement") {
989     $implIncludes{"kjs_dom.h"} = 1;
990     $implIncludes{"HTMLCanvasElement.h"} = 1;
991     return "toJS(exec, $value)";
992   } elsif ($type eq "CanvasGradient" or $type eq "Counter" or $type eq "Range") {
993     $implIncludes{"JS$type.h"} = 1;
994     return "toJS(exec, $value)";
995   } elsif ($type eq "NodeIterator" or
996            $type eq "TreeWalker") {
997     $implIncludes{"kjs_traversal.h"} = 1;
998     return "toJS(exec, $value)";
999   } elsif ($type eq "DOMWindow") {
1000     $implIncludes{"kjs_window.h"} = 1;
1001     return "toJS(exec, $value)";
1002   } elsif ($type eq "DOMObject") {
1003     $implIncludes{"JSCanvasRenderingContext2DBase.h"} = 1;
1004     return "toJS(exec, $value)";
1005   } else {
1006     die "Don't know how to convert a value of type $type to a JS Value";
1007   }
1008   
1009   die ("$value " . $signature->type);
1010 }
1011
1012 # Internal Helper
1013 sub GenerateHashTable
1014 {
1015   my $object = shift;
1016
1017   my $name = shift;
1018   my $size = shift;
1019   my $keys = shift;
1020   my $values = shift;
1021   my $specials = shift;
1022   my $parameters = shift;
1023
1024   # Helpers
1025   my @table = ();
1026   my @links = ();
1027
1028   my $maxDepth = 0;
1029   my $collisions = 0;
1030   my $savedSize = $size;
1031
1032   # Collect hashtable information...
1033   my $i = 0;
1034   foreach(@{$keys}) {
1035     my $depth = 0;
1036     my $h = $object->GenerateHashValue($_) % $savedSize;
1037
1038     while(defined($table[$h])) {
1039       if(defined($links[$h])) {
1040         $h = $links[$h];
1041         $depth++;
1042       } else {
1043         $collisions++;
1044         $links[$h] = $size;
1045         $h = $size;
1046         $size++;
1047       }
1048     }
1049   
1050     $table[$h] = $i;
1051
1052     $i++;
1053     $maxDepth = $depth if($depth > $maxDepth);
1054   }
1055
1056   # Ensure table is big enough (in case of undef entries at the end)
1057   if($#table + 1 < $size) {
1058     $#table = $size - 1;
1059   }
1060
1061   # Start outputing the hashtables...
1062   my $nameEntries = "${name}Entries";
1063   $nameEntries =~ s/:/_/g;
1064
1065   # first, build the string table
1066   my %soffset = ();
1067   if(($name =~ /Proto/) or ($name =~ /Constructor/)) {
1068     my $type = $name;
1069     my $implClass;
1070
1071     if($name =~ /Proto/) {
1072       $type =~ s/Proto.*//;
1073       $implClass = $type; $implClass =~ s/Wrapper$//;
1074       push(@implContent, "/* Hash table for prototype */\n");
1075     } else {
1076       $type =~ s/Constructor.*//;
1077       $implClass = $type; $implClass =~ s/Constructor$//;
1078       push(@implContent, "/* Hash table for constructor */\n");
1079     }
1080   } else {
1081     push(@implContent, "/* Hash table */\n");
1082   }
1083
1084   # Dump the hash table...
1085   push(@implContent, "\nstatic const HashEntry $nameEntries\[\] =\n\{\n");
1086
1087   $i = 0;
1088   foreach $entry (@table) {
1089     if(defined($entry)) {
1090       my $key = @$keys[$entry];
1091
1092       push(@implContent, "    \{ \"" . $key . "\"");
1093       push(@implContent, ", " . @$values[$entry]);
1094       push(@implContent, ", " . @$specials[$entry]);
1095       push(@implContent, ", " . @$parameters[$entry]);
1096       push(@implContent, ", ");
1097
1098       if(defined($links[$i])) {
1099         push(@implContent, "&${nameEntries}[$links[$i]]" . " \}");
1100       } else {
1101         push(@implContent, "0 \}");
1102       }
1103     } else {
1104       push(@implContent, "    \{ 0, 0, 0, 0, 0 \}");
1105     }
1106
1107     push(@implContent, ",") unless($i eq $size - 1);
1108     push(@implContent, "\n");
1109
1110     $i++;
1111   }
1112
1113   push(@implContent, "};\n\n");
1114   push(@implContent, "static const HashTable $name = \n");
1115   push(@implContent, "{\n    2, $size, $nameEntries, $savedSize\n};\n\n");
1116 }
1117
1118 # Internal helper
1119 sub GenerateHashValue
1120 {
1121   my $object = shift;
1122
1123   @chars = split(/ */, $_[0]);
1124
1125   # This hash is designed to work on 16-bit chunks at a time. But since the normal case
1126   # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
1127   # were 16-bit chunks, which should give matching results
1128
1129   my $EXP2_32 = 4294967296;
1130
1131   my $hash = 0x9e3779b9;
1132   my $l    = scalar @chars; #I wish this was in Ruby --- Maks
1133   my $rem  = $l & 1;
1134   $l = $l >> 1;
1135
1136   my $s = 0;
1137
1138   # Main loop
1139   for (; $l > 0; $l--) {
1140     $hash   += ord($chars[$s]);
1141     my $tmp = (ord($chars[$s+1]) << 11) ^ $hash;
1142     $hash   = (($hash << 16)% $EXP2_32) ^ $tmp;
1143     $s += 2;
1144     $hash += $hash >> 11;
1145   }
1146
1147   # Handle end case
1148   if ($rem !=0) {
1149     $hash += ord($chars[$s]);
1150     $hash ^= (($hash << 11)% $EXP2_32);
1151     $hash += $hash >> 17;
1152   }
1153
1154   # Force "avalanching" of final 127 bits
1155   $hash ^= ($hash << 3);
1156   $hash += ($hash >> 5);
1157   $hash = ($hash% $EXP2_32);
1158   $hash ^= (($hash << 2)% $EXP2_32);
1159   $hash += ($hash >> 15);
1160   $hash = $hash% $EXP2_32;
1161   $hash ^= (($hash << 10)% $EXP2_32);
1162   
1163   # this avoids ever returning a hash code of 0, since that is used to
1164   # signal "hash not computed yet", using a value that is likely to be
1165   # effectively the same as 0 when the low bits are masked
1166   $hash = 0x80000000  if ($hash == 0);
1167
1168   return $hash;
1169 }
1170
1171 # Internal helper
1172 sub WriteData
1173 {
1174   if (defined($IMPL)) {
1175     # Write content to file.
1176     print $IMPL @implContentHeader;
1177   
1178     foreach my $implInclude (sort keys(%implIncludes)) {
1179       print $IMPL "#include \"$implInclude\"\n";
1180     }
1181
1182     print $IMPL @implContent;
1183     close($IMPL);
1184     undef($IMPL);
1185
1186     @implHeaderContent = "";
1187     @implContent = "";    
1188     %implIncludes = ();
1189   }
1190
1191   if (defined($HEADER)) {
1192     # Write content to file.
1193     print $HEADER @headerContent;
1194     close($HEADER);
1195     undef($HEADER);
1196
1197     @headerContent = "";
1198   }
1199 }
1200
1201 sub constructorFor
1202 {
1203     my $className = shift;
1204     my $interfaceName = shift;
1205     
1206 my $implContent = << "EOF";
1207 class ${className}Constructor : public DOMObject {
1208 public:
1209     ${className}Constructor(ExecState* exec) 
1210     { 
1211         setPrototype(exec->lexicalInterpreter()->builtinObjectPrototype()); 
1212     }
1213     virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
1214     JSValue* getValueProperty(ExecState*, int token) const;
1215     virtual const ClassInfo* classInfo() const { return &info; }
1216     static const ClassInfo info;    
1217 };
1218
1219 const ClassInfo ${className}Constructor::info = { "${interfaceName}Constructor", 0, &${className}ConstructorTable, 0 };
1220
1221 bool ${className}Constructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1222 {
1223     return getStaticValueSlot<${className}Constructor, DOMObject>(exec, &${className}ConstructorTable, this, propertyName, slot);
1224 }
1225
1226 JSValue* ${className}Constructor::getValueProperty(ExecState*, int token) const
1227 {
1228     // The token is the numeric value of its associated constant
1229     return jsNumber(token);
1230 }
1231
1232 EOF
1233
1234     return $implContent;
1235 }
1236
1237 sub protoFuncFor
1238 {
1239     my $className = shift;
1240     
1241 my $implContent = << "EOF";
1242 class ${className}ProtoFunc : public InternalFunctionImp {
1243 public:
1244     ${className}ProtoFunc(ExecState* exec, int i, int len, const Identifier& name)
1245     : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name)
1246     , id(i)
1247     {
1248         put(exec, lengthPropertyName, jsNumber(len), DontDelete|ReadOnly|DontEnum);
1249     }
1250     virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List& args);
1251 private:
1252     int id;
1253 };
1254
1255 EOF
1256   
1257     return $implContent;
1258 }
1259
1260 sub toFunctionsFor
1261 {
1262     my $className = shift;
1263     my $implClassName = shift;
1264     my $interfaceName = shift;
1265
1266 my $implContent = << "EOF";
1267 KJS::JSValue* toJS(KJS::ExecState* exec, $implClassName* obj)
1268 {
1269     return KJS::cacheDOMObject<$implClassName, $className>(exec, obj);
1270 }
1271 $implClassName* to${interfaceName}(KJS::JSValue* val)
1272 {
1273     return val->isObject(&${className}::info) ? static_cast<$className*>(val)->impl() : 0;
1274 }
1275 EOF
1276
1277     return $implContent;
1278 }
1279
1280 1;