View Javadoc

1   /*
2    * Copyright (c) 2001-2005,
3    * RedVerst Group, ISP RAS http://www.ispras.ru
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are met:
8    *
9    * 1. Redistributions of source code must retain the above copyright notice, this
10   *    list of conditions and the following disclaimer.
11   *
12   * 2. Redistributions in binary form must reproduce the above copyright notice,
13   *    this list of conditions and the following disclaimer in the documentation
14   *    and/or other materials provided with the distribution.
15   *
16   * 3. The names "ATP", "TreeDL", "RedVerst", "ISP RAS"
17   *    may not be used to endorse or promote products derived from this software
18   *    without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   */
31  
32  package com.unitesk.atp.treedl;
33  
34  import java.io.File;
35  import java.io.FileOutputStream;
36  import java.io.IOException;
37  import java.io.PrintWriter;
38  
39  import com.unitesk.atp.tool.PluginClass;
40  import com.unitesk.atp.treedl.ParameterVariantMatrix.Variant;
41  import com.unitesk.atp.treedl.TDL.*;
42  
43  /***
44   * @author <A href="mailto:demakov@ispras.ru">Alexey Demakov</A>
45   * @version $Id: JavaNodeGenerator.java,v 1.68 2006/02/16 11:19:49 all-x Exp $
46   */
47  public class JavaNodeGenerator extends JavaTextGenerator implements TDL_Visitor
48  {
49      /***
50       * {@inheritDoc}
51       */
52      public String getVersion()
53      {
54          return PluginClass.getRevision( "$Revision: 1.68 $" ) + "-beta";
55      }
56  
57      protected PrintWriter smap;
58  
59      public static final String PROPERTY_NODE_CLASS = "node.class";
60      public static final String DEFAULT_NODE_CLASS = "com.unitesk.atp.tree.TreeClass.NodeClass";
61  
62      public static final String PROPERTY_SMAP_GENERATE = "smap.generate";
63      public static final String DEFAULT_SMAP_GENERATE = "false";
64      
65      public static final String PROPERTY_NODE_DEFAULT_CONSTRUCTOR = "node.default.constructor";
66      public static final String DEFAULT_NODE_DEFAULT_CONSTRUCTOR = "false";
67  
68      public static final String PROPERTY_ATTRIBUTE_CHECK_SETONCE = "attribute.check.setonce";
69      public static final String DEFAULT_ATTRIBUTE_CHECK_SETONCE = "true";
70  
71      public static final String PROPERTY_ATTRIBUTE_CHECK_NULL = "attribute.check.null";
72      public static final String DEFAULT_ATTRIBUTE_CHECK_NULL = "true";
73  
74      public static final String PROPERTY_ATTRIBUTE_CHECK_SIZE = "attribute.check.size";
75      public static final String DEFAULT_ATTRIBUTE_CHECK_SIZE = "true";
76  
77      public static final String PROPERTY_ATTRIBUTE_BOOL_IS = "attribute.bool.is";
78      public static final String DEFAULT_ATTRIBUTE_BOOL_IS = "false";
79  
80      public static final String PROPERTY_ATTRIBUTE_LIST_ADD = "attribute.list.add";
81      public static final String DEFAULT_ATTRIBUTE_LIST_ADD = "false";
82  
83      public static final String PROPERTY_ATTRIBUTE_LIST_REMOVE = "attribute.list.remove";
84      public static final String DEFAULT_ATTRIBUTE_LIST_REMOVE = "false";
85  
86      public static final String PROPERTY_ATTRIBUTE_LIST_SIZE = "attribute.list.size";
87      public static final String DEFAULT_ATTRIBUTE_LIST_SIZE = "true";
88  
89      public static final String PROPERTY_ATTRIBUTE_LIST_GET = "attribute.list.get";
90      public static final String DEFAULT_ATTRIBUTE_LIST_GET = "true";
91  
92      public static final String PROPERTY_ATTRIBUTE_LIST_MIN = "attribute.list.min";
93      public static final String DEFAULT_ATTRIBUTE_LIST_MIN = "0";
94  
95      public static final String PROPERTY_ATTRIBUTE_LIST_MAX = "attribute.list.max";
96      public static final String DEFAULT_ATTRIBUTE_LIST_MAX = "-1";
97  
98      public static final String PROPERTY_ATTRIBUTE_ENUM_CHECK = "attribute.enum.check";
99      public static final String DEFAULT_ATTRIBUTE_ENUM_CHECK = "true";
100 
101     public static final String PROPERTY_OPERATION_PUBLIC = "operation.public";
102     public static final String DEFAULT_OPERATION_PUBLIC = "true";
103 
104     public static final String PROPERTY_OPERATION_STATIC = "operation.static";
105     public static final String DEFAULT_OPERATION_STATIC = "true";
106 
107     protected void openSmap()
108     {
109         if( Boolean.getBoolean( getProperty( PROPERTY_SMAP_GENERATE, DEFAULT_SMAP_GENERATE ) ) )
110         {
111             String outFile = getOutFile().toString();
112             outFile = outFile.substring( 0, outFile.length() - ".java".length() );
113             File smapFileName = new File( outFile + ".smap" );
114             outFile = getOutFile().getName();
115             outFile = outFile.substring( 0, outFile.length() - ".java".length() );
116             try
117             {
118                 smap = new PrintWriter( new FileOutputStream( smapFileName.getCanonicalPath() ) );
119                 smap.println( "SMAP" );
120                 smap.println( outFile + ".java" );
121                 smap.println( "TDL" );
122                 smap.println( "*S TDL" );
123                 smap.println( "*F" );
124                 smap.println( "+ 0 " + outFile + ".tdl" );
125                 smap.println( outFile + ".tdl" );
126                 smap.println( "*L" );
127             } 
128             catch( IOException e )
129             {
130                 process( e );
131             }
132         }
133     }
134     
135     protected void closeSmap()
136     {
137         if( smap != null )
138         {
139             smap.println( "*E" );
140             smap.close();
141         }
142     }    
143     
144     protected void putMapping( int inputLine, int outputLine, int repeatCount )
145     {
146         if( smap != null )
147         {
148             smap.println( inputLine + "," + repeatCount + ":" + outputLine );
149         }
150     }
151     
152     public void visitModule( Module node )
153     {
154         openSmap();
155         
156         setFunction( "PredefinedTypeName", new PredefinedTypeNameFunction() );
157         setFunction( "Up", new NameFunction() );
158         setFunction( "ElementType", new ElementTypeFunction() );
159         setFunction( "ElementObjectType", new ElementObjectTypeFunction() );
160 
161         generateHeader();
162 
163         if( node.getName().sizeIdList() > 1 )
164         {
165             nl();
166             txt( "package " );
167             list( "i", 0, node.getName().sizeIdList() - 1, "${name.idList[i]}", "." );
168             txt( ";" ); nl();
169         }
170 
171         if( node.getOptHeader() != null )
172         {
173             nl();
174             txt( "//-----------------------------------------------------------------------------" ); nl();
175             txt( "// tree header" ); nl();
176             int outputLine = getLine();
177             int inputLine = node.getOptHeader().getPosition().getLine();
178             txt( "${optHeader}" ); nl();
179             int repeatCount=getLine()-outputLine;
180             putMapping(inputLine,outputLine,repeatCount);
181             txt( "//-----------------------------------------------------------------------------" ); nl();
182         }
183 
184         if( node.getOptDocomment() != null )
185         {
186             nl();
187             txt( "${optDocomment}" ); nl();
188         }
189 
190         nl();
191         txt( "public class ${name.idList[-1]} extends " );
192         if( node.sizeOptBaseCustomTypeList() > 0 )
193         {
194             txt( "${optBaseCustomTypeList[0]}" ); nl();
195             if( node.sizeOptBaseCustomTypeList() > 1 )
196             {
197                 txt( "implements " );
198                 list( "i"
199                     , 1
200                     , node.sizeOptBaseCustomTypeList()
201                     , "${optBaseCustomTypeList[i]}"
202                     , ", "
203                     );
204                 nl();
205             }
206         } else {
207             txt( "com.unitesk.atp.tree.TreeClass" ); nl();
208         }
209         block();
210 
211         if( node.getOptRootNodeType() != null )
212         {
213             nl();
214             txt( "//-----------------------------------------------------------------------------" ); nl();
215             txt( "// root of tree" ); nl();
216             nl();
217             txt( "public ${optRootNodeType.name} getRoot()" ); nl();
218             block_nl();
219             txt( "return (${optRootNodeType.name})getRootNode();" ); nl();
220             unblock_nl();
221             nl();
222             txt( "public void setRoot( ${optRootNodeType.name} node )" ); nl();
223             block_nl();
224             txt( "setRootNode( node );" ); nl();
225             unblock_nl();
226         }
227         
228         if( node.getOptBody() != null )
229         {
230             nl();
231             txt( "//-----------------------------------------------------------------------------" ); nl();
232             txt( "// tree body" ); nl();
233             int outputLine = getLine();
234             int inputLine = node.getOptBody().getPosition().getLine();       
235             txt( "${optBody}" ); nl();
236             int repeatCount=getLine()-outputLine;
237             putMapping(inputLine,outputLine,repeatCount);
238             txt( "//-----------------------------------------------------------------------------" ); nl();
239             nl();
240         }
241 
242         list( "memberIndex", 0, node.sizeOptMemberList(), "${optMemberList[memberIndex]}", null );
243 
244         if( node.getVisitorName().length() > 0 )
245         {
246             nl();
247             txt( "public static interface ${visitorName}" ); nl();
248             txt( "extends ${.Visitor}" ); nl();
249             list( "i"
250                 , 0
251                 , node.sizeOptBaseModuleList()
252                 , "      , ${optBaseModuleList[i].module.root.name}.${optBaseModuleList[i].module.root.visitorName}" + endl
253                 , null
254                 );
255             block_nl();
256             for( int i = 0; i < node.sizeOptMemberList(); i++ )
257             {
258                 ModuleMember member = node.getOptMemberList( i );
259                 if(    member instanceof NodeTypeDecl 
260                     && !((NodeTypeDecl)member).isAbstract() 
261                   )
262                 {
263                     pushNode( member );
264                     txt( "void visit${name}( ${name} node );" ); nl();
265                     popNode();
266                 }
267             }
268             unblock_nl();
269         }
270         
271         unblock_nl();
272         
273         closeSmap();
274     }
275 
276     public void visitBaseModule( BaseModule node )
277     {
278         // processed in visitModule
279         throw new UnsupportedOperationException();
280     }
281 
282     public void visitConstTypeDecl( ConstTypeDecl node )
283     {
284         nl();
285         txt( "public static final class ${name} extends ${.EnumClass}" ); nl();
286         block_nl();
287         txt( "public interface Key" );
288         txtif( node.getOptBaseType(), " extends ${optBaseType}.Key" ); nl();
289         block_nl();
290         Object old_i = getVariable( "i" );
291         for( int i = 0
292            ; i < node.sizeFullConstantList()
293            ; i++ 
294            )
295         {
296             setVariable( "i", new Integer( i ) );
297             txt( "public static final int ${fullConstantList[i]} = " );
298             if( i > 0 )
299             {
300                 txtAsIs( node.getFullConstantList( i - 1 ).toString() );
301                 txtif( node.isFlags(), " << ", " + " );
302             }
303             txt( "1;" ); nl();
304         }
305         unblock_nl();
306         setVariable( "i", old_i );
307         nl();
308         list( "i"
309             , 0
310             , node.sizeFullConstantList()
311             , "public static final ${name} ${fullConstantList[i]} = new ${name}( Key.${fullConstantList[i]} );"
312             , endl 
313             ); nl();
314         nl();
315         txt( "private static java.util.Map/*Integer,${name}*/ keyConstantMap = new java.util.HashMap/*Integer,${name}*/();" ); nl();
316         nl();
317         txt( "static" ); nl();
318         block_nl();
319         list( "i"
320                 , 0
321                 , node.sizeFullConstantList()
322                 , "keyConstantMap.put( new Integer( Key.${fullConstantList[i]} ), ${fullConstantList[i]} );"
323                 , endl 
324                 ); nl();
325         unblock_nl();
326         nl();
327         txt( "public static int min()" ); nl();
328         block_nl();
329         txtif( node.isFlags()
330              , "return 0;"
331              , "return Key.${fullConstantList[0]};" 
332              ); nl();
333         unblock_nl();
334         nl();
335         txt( "public static int max()" ); nl();
336         block_nl();
337         txtif( node.isFlags()
338              , "return (Key.${fullConstantList[-1]} << 1) - 1;"
339              , "return Key.${fullConstantList[-1]};"
340              ); nl();
341         unblock_nl();
342         nl();
343         txt( "public static ${name} get( int key )" ); nl();
344         block_nl();
345         txt( "if( key < min() || max() < key )" ); nl();
346         block_nl();
347         // TODO: use special exception type
348         txt( "throw new java.lang.IllegalArgumentException( \"${name}.get(\" + key + \")\" );" ); nl();
349         unblock_nl();
350         // TODO: don't create Integer
351         txt( "Integer keyObject = new Integer( key );" ); nl();
352         txt( "${name} constant = (${name})keyConstantMap.get( keyObject );" ); nl();
353         txt( "if( constant == null )" ); nl();
354         block_nl();
355         txt( "constant = new ${name}( key );" ); nl();
356         txt( "keyConstantMap.put( keyObject, constant );" ); nl();
357         unblock_nl();
358         txt( "return constant;" ); nl();
359         unblock_nl();
360         nl();
361         txt( "private ${name}( int key ) { super( key ); }" ); nl();
362         nl();
363         txt( "private Object readResolve() { return get( key() ); }" ); nl();
364         unblock_nl();
365     }
366     
367     public void visitNodeTypeDecl( NodeTypeDecl node )
368     {
369         // header
370         if( node.getOptDocomment() != null )
371         {
372             nl();
373             txt( "${optDocomment}" );
374         }
375         nl();
376         txt( "public" );
377         txtif( node.isAbstract(), " abstract" );
378         txt( " static class ${name}" );
379 
380         boolean hasBaseClass = false;
381 
382         String defaultClass = getProperty( node, PROPERTY_NODE_CLASS, DEFAULT_NODE_CLASS, true );
383         if( defaultClass.length() != 0 )
384         {
385             setVariable( "defaultClass", defaultClass );
386         } else {
387             defaultClass = null;
388         }
389         
390         if( node.getOptBaseType() != null )
391         {
392             if( node.getOptBaseType().getType() != TDL_Module.getRootNodeType() )
393             {
394                 txt( " extends ${optBaseType}" );
395             } else {
396                 txtif( defaultClass != null, " extends ${.defaultClass}" );
397             }
398             hasBaseClass = true;
399         } else {
400             if( defaultClass != null )
401             {
402                 txt( " extends ${.defaultClass}" );
403                 hasBaseClass = true;
404             }
405         }
406 
407         if( node.sizeOptBaseCustomTypeList() > 0 )
408         {
409             int implementsStart = 0;
410             if( !hasBaseClass )
411             {
412                 txt( " extends ${optBaseCustomTypeList[0]}" );
413                 implementsStart++;
414             }
415 
416             if( node.sizeOptBaseCustomTypeList() > implementsStart )
417             {
418                 txt( " implements " );
419                 list( "i"
420                     , implementsStart
421                     , node.sizeOptBaseCustomTypeList()
422                     , "${optBaseCustomTypeList[i]}"
423                     , ", "
424                     );
425             }
426         }
427 
428         nl();
429         block_nl();
430         
431         // members
432         list( "i", 0, node.sizeOptMemberList(), "${optMemberList[i]}", null );
433 
434         // constructor
435         txt( "//-------------------------------------------------------------------------" ); nl();
436         txt( "// constructor" ); nl();
437         nl();
438         txt( "public" ); nl();
439         txt( "${name}" );
440 
441         int constructorParametersCount = 0;
442         for( int i = 0; i < node.sizeFullFieldList(); i++ )
443         {
444             Field field = node.getFullFieldList( i );
445 
446             if( TDL_Module.isConstructorParameter( field ) )
447             {
448                 pushNode( field );
449 
450                 nl();
451                 txtif( constructorParametersCount == 0, "(", "," );
452                 txt( " ${type} ${name}" );
453                 constructorParametersCount++;
454 
455                 popNode();
456             }
457         }
458 
459         switch( constructorParametersCount )
460         {
461         case 0:
462             txt( "()" );
463             break;
464         case 1:
465             txt( " )" );
466             break;
467         default:
468             nl();
469             txt( ")" );
470             break;
471         }
472         nl();
473         block_nl();
474         txt( "super" );
475 
476         int parentConstructorParametersCount = 0;
477 
478         for( int i = 0; i < node.getBaseNodeType().sizeFullFieldList(); i++ )
479         {
480             Field field = node.getBaseNodeType().getFullFieldList( i );
481 
482             if( TDL_Module.isConstructorParameter( field ) )
483             {
484                 pushNode( field );
485 
486                 nl();
487                 txtif( parentConstructorParametersCount == 0, "(", "," );
488 
489                 txt( " ${name}" );
490                 parentConstructorParametersCount++;
491 
492                 popNode();
493             }
494         }
495 
496         switch( parentConstructorParametersCount )
497         {
498         case 0:
499             txt( "();" );
500             break;
501         case 1:
502             txt( " );" );
503             break;
504         default:
505             nl();
506             txt( ");" );
507             break;
508         }
509         nl();
510         nl();
511 
512         for( int i = node.getBaseNodeType().sizeFullFieldList()
513            ; i < node.sizeFullFieldList()
514            ; i++ 
515            )
516         {
517             Field field = node.getFullFieldList( i );
518 
519             if( TDL_Module.isConstructorParameter( field ) )
520             {
521                 pushNode( field );
522 
523                 txt( "set${Up:name}( ${name} );" ); nl();
524 
525                 popNode();
526             } else if( field.getOptInitCode() != null )
527             {
528                 pushNode( field );
529                 int outputLine = getLine();
530                 int inputLine = field.getOptInitCode().getPosition().getLine();       
531 
532                 txt( "set${Up:name}( ${optInitCode} );" ); nl();
533                 int repeatCount=getLine()-outputLine;
534                 putMapping(inputLine,outputLine,repeatCount);
535 
536                 popNode();
537             }
538         }
539 
540         for( int i = 0; i < node.sizeOptMemberList(); i++ )
541         {
542             NodeMember member = node.getOptMemberList( i );
543 
544             if( member instanceof ConstructorCodeMember )
545             {
546                 pushNode( member );
547                 txt( "//---------------------------------------------------------------------" ); nl();
548                 txt( "// constructor code" ); nl();
549                 int outputLine = getLine();
550                 int inputLine = member.getPosition().getLine();       
551                 txt( "${code}" );
552                 int repeatCount=getLine()-outputLine+1;
553                 putMapping(inputLine,outputLine,repeatCount);
554  
555                 popNode();
556             }
557         }
558 
559         unblock_nl();
560         
561         if( getBooleanProperty( node
562                               , PROPERTY_NODE_DEFAULT_CONSTRUCTOR
563                               , DEFAULT_NODE_DEFAULT_CONSTRUCTOR
564                               , true
565                               )
566           )
567         {
568             if( constructorParametersCount > 0 )
569             {
570                 nl();
571                 txt( "//-------------------------------------------------------------------------" ); nl();
572                 txt( "// default constructor" ); nl();
573                 txt( "public ${name}() {}" ); nl();
574             }
575         }
576 
577         // key
578         if(    node.getBaseNodeType() == TDL_Module.getRootNodeType() 
579             || node.getBaseNodeType().getParent() != node.getParent()
580           )
581         {
582             // if module of base node type differs from module of this node type
583             nl();
584             txt( "public Class keyClass()" ); nl();
585             block_nl();
586             txt( "return ${parent.name.idList[-1]}.class;" ); nl();
587             unblock_nl();
588         }
589         if( !node.isAbstract() )
590         {
591             nl();
592             txt( "public static final int KEY = ${.memberIndex};" ); nl();
593             nl();
594             txt( "public int key()" ); nl();
595             block_nl();
596             txt( "return KEY;" ); nl();
597             unblock_nl();
598         }
599         
600         // accept
601         String visitorName = ((Module)node.getParent()).getVisitorName();
602         if( visitorName.length() > 0 && !node.isAbstract() )
603         {
604             nl();
605             txt( "//-------------------------------------------------------------------------" ); nl();
606             txt( "// visitor design pattern" ); nl();
607             nl();
608             txt( "public void accept( ${.Visitor} visitor )" ); nl();
609             block_nl();
610             txt( "((${parent.visitorName})visitor).visit${name}( this );" ); nl();
611             unblock_nl();
612         }
613         unblock_nl();
614     }
615     
616     public void visitConstructorCodeMember( ConstructorCodeMember node )
617     {
618     }
619 
620     public void visitBodyCodeMember( BodyCodeMember node )
621     {
622         nl();
623         txt( "//---------------------------------------------------------------------" ); nl();
624         txt( "// body code" ); nl();
625         int outputLine = getLine();
626         int inputLine = node.getPosition().getLine();       
627         txt( "${code}" );nl();
628         int repeatCount=getLine()-outputLine;
629         putMapping(inputLine,outputLine,repeatCount);
630     }
631 
632     public void visitField( Field node )
633     {
634         Field baseField = node.getBaseField();
635         
636         txt( "//-------------------------------------------------------------------------" ); nl();
637         txtif( node.isChild()
638              , "// child"
639              , "// attribute" 
640              ); nl();
641 
642         if( TDL_Module.getStorageType( node ) == StorageType.DEFAULT )
643         {
644             nl();
645             txt( "private ${type} ${name};" ); nl();
646         }
647 
648         // get
649         if( baseField == null && !TDL_Module.hasGet( node ) )
650         {
651             nl();
652             if( node.getOptDocomment() != null )
653             {
654                 txt( "${optDocomment}" ); nl();
655             }
656             /*
657              * abstract get-method for the first abstract 
658              * or custom w/o get-code attribute.
659              */
660             txt( "public abstract ${type} get${Up:name}();" ); nl();
661             nl();
662         } else
663         if(    TDL_Module.getStorageType( node ) == StorageType.DEFAULT 
664             || node.getOptGetCode() != null
665           )
666         {
667             nl();
668             if( node.getOptDocomment() != null )
669             {
670                 txt( "${optDocomment}" ); nl();
671             }
672             /*
673              * get-method implementation:
674              * 1. for the first non-abstract attribute
675              * 2. if there is get-code
676              */
677             txt( "public ${type} get${Up:name}()" ); nl();
678             block_nl();
679             if( baseField != null && TDL_Module.hasGet( baseField ) )
680             {
681                 // call super get
682                 txt( "${type} ${name} = super.get${Up:name}();" ); nl();
683             } else
684             if( TDL_Module.getStorageType( node ) != StorageType.DEFAULT )
685             {
686                 // uninited local variable
687                 txt( "${type} ${name};" ); nl();
688             }
689                 // else field ${name} is defined
690             if( node.getOptGetCode() != null )
691             {
692                 int outputLine = getLine();
693                 int inputLine = node.getOptGetCode().getPosition().getLine();       
694                 txt( "${optGetCode}" ); nl();
695                 int repeatCount=getLine()-outputLine;
696                 putMapping(inputLine,outputLine,repeatCount);
697             }
698             txt( "return ${name};" ); nl();
699             unblock_nl();
700         }
701         
702         // set
703         if( !node.checkModifiers( Modifiers.NOSET ) )
704         {
705             if( baseField == null && !TDL_Module.hasSet( node ) )
706             {
707                 nl();
708                 /*
709                  * abstract set-method for the first abstract attribute.
710                  */
711                 txt( "public abstract void set${Up:name}( ${type} ${name} );" ); nl();
712                 nl();
713             } else
714             if(    TDL_Module.getStorageType( node ) == StorageType.DEFAULT 
715                 || node.getOptSetCode() != null
716               )
717             {
718                 boolean setonceCheck = false;
719                 if(    getBooleanProperty( node
720                                          , PROPERTY_ATTRIBUTE_CHECK_SETONCE
721                                          , DEFAULT_ATTRIBUTE_CHECK_SETONCE
722                                          , true
723                                          ) 
724                     && node.checkModifiers( Modifiers.SETONCE )
725                     && (    baseField == null
726                          || !TDL_Module.hasSet( baseField )
727                        )
728                   )                
729                 {
730                     nl();
731                     txt( "private boolean __is${Up:name}Inited__ = false;" ); nl();
732                     setonceCheck = true;
733                 }
734                 
735                 nl();
736                 txt( "public void set${Up:name}( ${type} ${name} )" ); nl();
737                 block_nl();
738 
739                 // readonly fields can be set only once
740                 if( setonceCheck )
741                 {
742                     txt( "if( __is${Up:name}Inited__ )" ); nl();
743                     block_nl();
744                     txt( "throw new java.lang.IllegalArgumentException( \"${name}\" );" ); nl();
745                     unblock_nl();
746                 }
747 
748                 if(    TDL_Module.getStorageType( node ) == StorageType.DEFAULT
749                     || TDL_Module.getStorageType( node ) == StorageType.CUSTOM
750                   )
751                 {
752                     // type checking
753                     Type type = node.getType();
754                     switch( type.getCardinality().key() )
755                     {
756                     case 0:
757                         if( JavaLanguageDescription.isPrimitiveType( type ) )
758                         {
759                             // no check for primitive type
760                             break;
761                         }
762                         // non-optional reference type
763                     case Cardinality.Key.LIST | Cardinality.Key.OPTIONAL:
764                         // non-optional
765                         if( getBooleanProperty( node
766                                               , PROPERTY_ATTRIBUTE_CHECK_NULL
767                                               , DEFAULT_ATTRIBUTE_CHECK_NULL
768                                               , true
769                                               )
770                           )
771                         {
772                             generateListCheck( getProperty( node, PROPERTY_ATTRIBUTE_LIST_MIN, "0", true )
773                                              , getProperty( node, PROPERTY_ATTRIBUTE_LIST_MAX, DEFAULT_ATTRIBUTE_LIST_MAX, true )
774                                              );
775                         }
776                         break;
777                     case Cardinality.Key.LIST:
778                         // list.size > 0
779                         if( getBooleanProperty( node
780                                               , PROPERTY_ATTRIBUTE_CHECK_SIZE
781                                               , DEFAULT_ATTRIBUTE_CHECK_SIZE
782                                               , true
783                                               )
784                           )
785                         {
786                             generateListCheck( getProperty( node, PROPERTY_ATTRIBUTE_LIST_MIN, "1", true )
787                                              , getProperty( node, PROPERTY_ATTRIBUTE_LIST_MAX, DEFAULT_ATTRIBUTE_LIST_MAX, true )
788                                              );
789                         }
790                         break;
791                     case Cardinality.Key.OPTIONAL:
792                         // TODO: add warning message
793 //                        if( JavaLanguageDescription.isPrimitiveType( type ) )
794 //                        {
795 //                             module
796 //                            .getMessageBox()
797 //                            .warning
798 //                             ( new OptionalPrimitiveTypeAttributeMessage
799 //                                   ( module.getFile()
800 //                                   , node.getName().getPosition()
801 //                                   , ((NameType)node.getType()).getName()
802 //                                   , node.getName().getValue()
803 //                                   )
804 //                             );
805 //                        }
806                         break;
807                     }
808                 } else
809                 if( TDL_Module.hasSet( baseField ) )
810                 {
811                     // call super set
812                     txt( "super.set${Up:name}( ${name} );" ); nl();
813                 }
814 
815                 if( node.getOptSetCode() != null )
816                 {
817                     int outputLine = getLine();
818                     int inputLine = node.getOptSetCode().getPosition().getLine();       
819                     txt( "${optSetCode}" ); nl();
820                     int repeatCount=getLine()-outputLine;
821                     putMapping(inputLine,outputLine,repeatCount);     
822                 }
823 
824                 // setonce fields can be set only once
825                 if( setonceCheck )
826                 {
827                     txt( "__is${Up:name}Inited__ = true;" ); nl();
828                 }
829 
830                 if( TDL_Module.getStorageType( node ) == StorageType.DEFAULT )
831                 {
832                     txt( "this.${name} = ${name};" ); nl();
833                     if( node.isChild() )
834                     {
835                         txt( "makeChild( \"${name}\" );" ); nl();
836                     }
837                 }
838                 unblock_nl();
839             }
840         }
841         if( baseField == null )
842         {
843             if( node.getType().checkCardinality( Cardinality.LIST ) )
844             {
845                 // list methods
846                 if( getBooleanProperty( node
847                                       , PROPERTY_ATTRIBUTE_LIST_GET
848                                       , DEFAULT_ATTRIBUTE_LIST_GET
849                                       , true
850                                       )
851                   )
852                 {
853                     // get( int )
854                     nl();
855                     txt( "public final ${ElementType:type} get${Up:name}( int i )" ); nl();
856                     block_nl();
857                     if( JavaLanguageDescription.isPrimitiveType( node.getType() ) )
858                     {
859                         txt( "return ((${ElementObjectType:type})get${Up:name}().get( i )).${ElementType:type}Value();" ); nl();
860                     } else {
861                         txt( "return (${ElementType:type})get${Up:name}().get( i );" ); nl();
862                     }
863                     unblock_nl();
864                 }
865 
866                 if( getBooleanProperty( node
867                                       , PROPERTY_ATTRIBUTE_LIST_SIZE
868                                       , DEFAULT_ATTRIBUTE_LIST_SIZE
869                                       , true
870                                       )
871                   )
872                 {
873                     // size
874                     nl();
875                     txt( "public final int size${Up:name}()" ); nl();
876                     block_nl();
877                     txt( "return get${Up:name}().size();" ); nl();
878                     unblock_nl();
879                 }
880                 
881                 if( getBooleanProperty( node
882                                       , PROPERTY_ATTRIBUTE_LIST_ADD
883                                       , DEFAULT_ATTRIBUTE_LIST_ADD
884                                       , true
885                                       )
886                   )
887                 {
888                     // add
889                     nl();
890                     txt( "public final void add${Up:name}( ${ElementType:type} elem )" ); nl();
891                     block_nl();
892                     txt( "get${Up:name}().add( elem );" ); nl();
893                     if( node.isChild() )
894                     {
895                         txt( "elem.setParent( this );" ); nl();
896                     }
897                     unblock_nl();
898                 }
899                 if( getBooleanProperty( node
900                                       , PROPERTY_ATTRIBUTE_LIST_REMOVE
901                                       , DEFAULT_ATTRIBUTE_LIST_REMOVE
902                                       , true
903                                       )
904                   )
905                 {
906                     // remove
907                     nl();
908                     txt( "public final void remove${Up:name}( int index )" ); nl();
909                     block_nl();
910                     if( node.isChild() )
911                     {
912                         txt( "((${.Node})get${Up:name}().remove( index )).resetParent();" ); nl();
913                     } else {
914                         txt( "get${Up:name}().remove( index );" ); nl();
915                     }
916                     unblock_nl();
917                 }
918                 nl();
919             } else {
920                 // boolean is()
921                 if(    node.getType() instanceof PredefinedType 
922                     && ((PredefinedType)node.getType()).checkKind( PredefinedTypeKind.BOOL) 
923                   )
924                 {
925                     if( getBooleanProperty( node
926                                           , PROPERTY_ATTRIBUTE_BOOL_IS
927                                           , DEFAULT_ATTRIBUTE_BOOL_IS
928                                           , true
929                                           )
930                       )
931                     {
932                         nl();
933                         if( node.getName().getValue().startsWith( "is" ) )
934                         {
935                             txt( "public final boolean ${name}()" ); nl();
936                         } else {
937                             txt( "public final boolean is${Up:name}()" ); nl();
938                         }
939                         block_nl();
940                         txt( "return get${Up:name}();" ); nl();
941                         unblock_nl();
942                         nl();
943                     }
944                 }
945                 // enum check
946                 if(    node.getType() instanceof NodeType 
947                     && ((NodeType)node.getType()).getType().getType() instanceof ConstTypeDecl
948                   )
949                 {
950                     if( getBooleanProperty( node
951                                           , PROPERTY_ATTRIBUTE_ENUM_CHECK
952                                           , DEFAULT_ATTRIBUTE_ENUM_CHECK
953                                           , true
954                                           )
955                       )
956                     {
957                         nl();
958                         generateEnumCheck( node );
959                     }
960                 }
961             }
962         }
963     }
964 
965     protected void generateListCheck( String min, String max )
966     {
967         boolean nullChecked = false;
968         if( !min.equals( DEFAULT_ATTRIBUTE_LIST_MIN ) )
969         {
970             setVariable( "min", min );
971             txt( "if( ${name}.size() < ${.min} )" ); nl();
972             block_nl();
973             txt( "throw new java.lang.IllegalArgumentException( \"${name}.size() < ${.min}\" );" ); nl();
974             unblock_nl();
975             nl();
976             nullChecked = true;
977         }
978         if( !max.equals( DEFAULT_ATTRIBUTE_LIST_MAX ) )
979         {
980             setVariable( "max", max );
981             txt( "if( ${name}.size() > ${.max} )" ); nl();
982             block_nl();
983             txt( "throw new java.lang.IllegalArgumentException( \"${name}.size() > ${.max}\" );" ); nl();
984             unblock_nl();
985             nl();
986             nullChecked = true;
987         }
988         if( !nullChecked )
989         {
990             txt( "if( ${name} == null )" ); nl();
991             block_nl();
992             txt( "throw new java.lang.IllegalArgumentException( \"${name} == null\" );" ); nl();
993             unblock_nl();
994             nl();
995         }
996     }
997     /***
998      * check( int ) for the first attribute of constant type
999      */
1000     protected void generateEnumCheck( Field node )
1001     {
1002         if( ((ConstTypeDecl)((NodeType)node.getType()).getType().getType()).isFlags() )
1003         {
1004             txt( "public boolean check${Up:name}( int mask )" ); nl();
1005             block_nl();
1006             txt( "return (get${Up:name}().key() & mask) == mask;" ); nl();
1007             unblock_nl();
1008         } else {
1009             txt( "public boolean check${Up:name}( int value )" ); nl();
1010             block_nl();
1011             txt( "return get${Up:name}().key() == value;" ); nl();
1012             unblock_nl();
1013         }
1014         nl();
1015         txt( "public boolean check${Up:name}( ${type} value )" ); nl();
1016         block_nl();
1017         txt( "return check${Up:name}( value.key() );" ); nl();
1018         unblock_nl();
1019         nl();
1020     }
1021 
1022     /***
1023      * Generate variant methods for all combinations of virtual node types parameters
1024      * 
1025      * @param operationDecl operation declaration to generate variants for
1026      * @param paramMatrix   matrix to generate variants for
1027      */
1028     protected void generateVariants( OperationDecl operationDecl, ParameterVariantMatrix paramMatrix )
1029     {
1030         ModuleMatrix moduleMatrix = operationDecl.getModuleMatrix();
1031         for( Index variant = paramMatrix.createIndex()
1032            ; variant.has()
1033            ; variant.next()
1034            )
1035         {
1036             nl();
1037             pushNode( operationDecl );
1038             txt( "private final " );
1039             txtif( getBooleanProperty( operationDecl
1040                                      , PROPERTY_OPERATION_STATIC
1041                                      , DEFAULT_OPERATION_STATIC
1042                                      , true 
1043                                      )
1044                  , "static " 
1045                  );
1046             txt( "${returnType?void} _${.memberIndex}_${name}( " );
1047             popNode();
1048             Object old_i = getVariable( "i" );
1049             for( int i = 0, vi = -1; i < operationDecl.sizeOptParameterDeclList(); i++ )
1050             {
1051                 setVariable( "i", new Integer( i ) );
1052                 txtif( i > 0, ", " );
1053                 ParameterDecl paramDecl = operationDecl.getOptParameterDeclList( i );
1054                 if( paramDecl instanceof VirtualParameterDecl )
1055                 {
1056                     vi++;
1057                     if( moduleMatrix.isNodeType( vi ) )
1058                     {
1059                         // variant type
1060                         Variant v = paramMatrix.getVariant( vi, variant.getIndex( vi ) );
1061                         setVariable( "variant", v );
1062                         txtif( ((Module)v.getType().getParent()) != module.getRoot()
1063                              , "${.variant.type.parent.name}." 
1064                              );
1065                         txt( "${.variant.type.name} ${optParameterDeclList[i].name}" );
1066                         continue;
1067                     }
1068                 }
1069                 txt( "${optParameterDeclList[i]}" );
1070             }
1071             setVariable( "i", old_i );
1072             txt( " )" ); nl();
1073             block_nl();
1074             if( moduleMatrix.getDimType() == moduleMatrix.getDim() )
1075             {
1076                 generateCaseCode( operationDecl, paramMatrix, variant );
1077             } else {
1078                 generateEnumSwitch( operationDecl, 0, paramMatrix, variant );
1079             }
1080             unblock_nl();
1081         }
1082     }
1083     
1084     /***
1085      * Generate case code for the given variant.
1086      */
1087     protected void generateCaseCode( OperationDecl operationDecl
1088                                    , ParameterVariantMatrix paramMatrix
1089                                    , Index paramIndex
1090                                    )
1091     {
1092         pushNode( paramMatrix.getCase( paramIndex ) );
1093         txt( "${parent.code}" ); nl();
1094         popNode();
1095     }
1096 
1097     /***
1098      * Generate variant call.
1099      */
1100     protected void generateCall( OperationDecl operationDecl, ParameterVariantMatrix paramMatrix, Index paramIndex )
1101     {
1102         ModuleMatrix moduleMatrix = operationDecl.getModuleMatrix();
1103         pushNode( operationDecl );
1104         txtif( operationDecl.getReturnType(), "return " );
1105         txt( "_${.memberIndex}_${name}( " );
1106         Object old_i = getVariable( "i" );
1107         Object old_variant = getVariable( "variant" );
1108         for( int i = 0, vi = 0; i < operationDecl.sizeOptParameterDeclList(); i++ )
1109         {
1110             txtif( i > 0, ", " );
1111             setVariable( "i", new Integer( i ) );
1112             ParameterDecl paramDecl = operationDecl.getOptParameterDeclList( i );
1113             if( paramDecl instanceof VirtualParameterDecl )
1114             {
1115                 if( moduleMatrix.isNodeType( vi ) )
1116                 {
1117                     // cast
1118                     Variant v = paramMatrix.getVariant( vi, paramIndex.getIndex( vi ) );
1119                     setVariable( "variant", v );
1120                     txt( "(" );
1121                     txtif( ((Module)v.getType().getParent()) != module.getRoot()
1122                             , "${.variant.type.parent.name}." 
1123                             );
1124                     txt( "${.variant.type.name})" );
1125                 }
1126                 vi++;
1127             }
1128             txt( "${optParameterDeclList[i].name}" );
1129         }
1130         setVariable( "variant", old_variant );
1131         setVariable( "i", old_i );
1132         txt( " );" ); nl();
1133         if( operationDecl.getReturnType() == null )
1134         {
1135             txt( "break;" ); nl();
1136         }
1137         popNode();
1138     }
1139 
1140     /***
1141      * Generate switch by enum type of virtual parameter
1142      *
1143      * @param index index of virtual parameter
1144      */
1145     protected void generateEnumSwitch( OperationDecl operationDecl
1146                                      , int index
1147                                      , ParameterVariantMatrix paramMatrix
1148                                      , Index paramIndex
1149                                      )
1150     {
1151         ModuleMatrix moduleMatrix = operationDecl.getModuleMatrix();
1152         if( index < moduleMatrix.getDim() )
1153         {
1154             if( moduleMatrix.isNodeType( index ) )
1155             {
1156                 generateEnumSwitch( operationDecl, index + 1, paramMatrix, paramIndex );
1157                 return;
1158             }
1159             pushNode( operationDecl.getOptParameterDeclList( moduleMatrix.getIndex( index ) ) );
1160             txt( "switch( ${name}.key() )" ); nl();
1161             block_nl();
1162             Object old_variant = getVariable( "variant" );
1163             for( int i = 0; i < paramMatrix.getSize( index ); i++ )
1164             {
1165                 Variant v = paramMatrix.getVariant( index, i );
1166                 setVariable( "variant", v );
1167                 Module m = (Module)v.getConstant().getParent().getParent();
1168                 txt( "case " );
1169                 txtif( m != module.getRoot()
1170                      , "${.variant.constant.parent.parent.name}." 
1171                      );
1172                 txt( "${.variant.constant.parent.name}.Key.${.variant.constant}:" ); nl();
1173                 block_nl();
1174                 paramIndex.setIndex( index, i );
1175                 generateEnumSwitch( operationDecl, index + 1, paramMatrix, paramIndex );
1176                 unblock_nl();
1177             }
1178             setVariable( "variant", old_variant );
1179             txt( "default:" ); nl(); incIndent();
1180             txt( "throw new IllegalArgumentException( \"${name}\" );" ); nl(); popIndent();
1181             unblock_nl();
1182             popNode();
1183         } else {
1184             generateCaseCode( operationDecl, paramMatrix, paramIndex );
1185             if( operationDecl.getReturnType() == null )
1186             {
1187                 txt( "break;" ); nl();
1188             }
1189         }
1190     }
1191     
1192     /***
1193      * Generate switch by key of virtual parameter
1194      * 
1195      *  @param index index of virtual parameter
1196      */
1197     protected void generateKeySwitch( OperationDecl operationDecl
1198                                     , int index
1199                                     , ParameterVariantMatrix paramMatrix
1200                                     , Index paramIndex
1201                                     )
1202     {
1203         ModuleMatrix moduleMatrix = operationDecl.getModuleMatrix();
1204         if( index < moduleMatrix.getDim() )
1205         {
1206             if( !moduleMatrix.isNodeType( index ) )
1207             {
1208                 generateKeySwitch( operationDecl, index + 1, paramMatrix, paramIndex );
1209                 return;
1210             }
1211             VirtualParameterDecl paramDecl 
1212                 = (VirtualParameterDecl)operationDecl
1213                  .getOptParameterDeclList( moduleMatrix.getIndex( index ) ); 
1214             pushNode( paramDecl );
1215             txt( "switch( ${name}.key() )" ); nl();
1216             block_nl();
1217             Object old_variant = getVariable( "variant" );
1218             for( int i = 0; i < paramMatrix.getSize( index ); i++ )
1219             {
1220                 Variant v = paramMatrix.getVariant( index, i );
1221                 Module m = (Module)v.getType().getParent();
1222                 setVariable( "variant", v );
1223                 txt( "case " );
1224                 txtif( m != module.getRoot()
1225                      , "${.variant.type.parent.name}." 
1226                      );
1227                 txt( "${.variant.type.name}.KEY:" ); nl();
1228                 block_nl();
1229                 paramIndex.setIndex( index, i );
1230                 generateKeySwitch( operationDecl, index + 1, paramMatrix, paramIndex );
1231                 unblock_nl();
1232             }
1233             setVariable( "variant", old_variant );
1234             txt( "default:" ); nl(); incIndent();
1235             txt( "throw new IllegalArgumentException( \"${name}\" );" ); nl(); popIndent();
1236             unblock_nl();
1237             popNode();
1238         } else {
1239             generateCall( operationDecl, paramMatrix, paramIndex );
1240         }
1241     }
1242     
1243     /***
1244      * Generate switch (if-else-if) by key class of virtual parameter
1245      * 
1246      *  @param index index of virtual parameter
1247      */
1248     protected void generateKeyClassSwitch( OperationDecl operationDecl
1249                                          , int index
1250                                          , Index moduleIndex
1251                                          )
1252     {
1253         ModuleMatrix matrix = operationDecl.getModuleMatrix();
1254         if( index < matrix.getDim() )
1255         {
1256             if( !matrix.isNodeType( index ) )
1257             {
1258                 generateKeyClassSwitch( operationDecl, index + 1, moduleIndex );
1259                 return;
1260             }
1261             VirtualParameterDecl paramDecl 
1262                 = (VirtualParameterDecl)operationDecl.getOptParameterDeclList( matrix.getIndex( index ) ); 
1263             pushNode( paramDecl );
1264             Module[] domain = matrix.getDomain();
1265             for( int i = 0 ; i < domain.length; i++ ) 
1266             {
1267                 Module m = domain[i];
1268                 if( matrix.variantsExist( m, index ) )
1269                 {
1270                     setVariable( "module", m.getName().getValue() );
1271                     nl();
1272                     txt( "if( ${name}.keyClass() == ${.module}.class )" ); nl();
1273                     block_nl();
1274                     moduleIndex.setIndex( index, i );
1275                     generateKeyClassSwitch( operationDecl, index + 1, moduleIndex );
1276                     unblock();
1277                     txt( " else" );
1278                 }
1279             }
1280             txtAsIs( " " );
1281             block_nl();
1282             txt( "throw new IllegalArgumentException( \"${name}\" );" ); nl();
1283             unblock_nl();
1284             popNode();
1285         } else {
1286             ParameterVariantMatrix paramMatrix = operationDecl.getModuleMatrix().getParamMatrix( moduleIndex );
1287             if( paramMatrix != null )
1288             {
1289                 generateKeySwitch( operationDecl, 0, paramMatrix, paramMatrix.createIndex() );
1290             } else {
1291                 OperationDecl opDecl = operationDecl.getModuleMatrix().getOperationDecl( moduleIndex );
1292                 pushNode( opDecl );
1293                 txtif( opDecl.getReturnType(), "return " );
1294                 txtif( opDecl.getParent() != module, "${parent.name}." );
1295                 txt( "${name}( " );
1296                 popNode();
1297                 pushNode( operationDecl );
1298                 list( "i", 0, operationDecl.sizeOptParameterDeclList(), "${optParameterDeclList[i].name}", ", " );
1299                 popNode();
1300                 txt( " );" ); nl();
1301                 if( operationDecl.getReturnType() == null )
1302                 {
1303                     txt( "break;" ); nl();
1304                 }
1305             }
1306         }
1307     }
1308 
1309     public void visitOperationDecl( OperationDecl node )
1310     {
1311         nl();
1312         txt( "//-----------------------------------------------------------------------------" ); nl();
1313         txt( "// operation ${name}" ); nl();
1314         
1315         ModuleMatrix matrix = node.getModuleMatrix();
1316         for( Index variant = matrix.createIndex()
1317            ; variant.has()
1318            ; variant.next()
1319            )
1320         {
1321             ParameterVariantMatrix paramMatrix = matrix.getParamMatrix( variant );
1322             if( paramMatrix != null )
1323             {
1324                 generateVariants( node, paramMatrix );
1325             }
1326         }
1327         nl();
1328         txtif( getBooleanProperty( node
1329                                  , PROPERTY_OPERATION_PUBLIC
1330                                  , DEFAULT_OPERATION_PUBLIC
1331                                  , true 
1332                                  )
1333              , "public " 
1334              );
1335         txtif( getBooleanProperty( node
1336                                  , PROPERTY_OPERATION_STATIC
1337                                  , DEFAULT_OPERATION_STATIC
1338                                  , true 
1339                                  )
1340              , "static " 
1341              );
1342         txt( "${returnType?void} ${name}( " );
1343         list( "i", 0, node.sizeOptParameterDeclList(), "${optParameterDeclList[i]}", ", " );
1344         txt( " )" ); nl();
1345         block_nl();
1346         
1347         generateKeyClassSwitch( node, 0, matrix.createIndex() );
1348         
1349 //        for( int i = 0; i < matrix.getDim(); i++ ) variant[i] = 0;
1350 //        if( matrix.getDimType() > 0 )
1351 //        {
1352 //            Module[] modules = new Module[matrix.getDim()];
1353 //            generateKeyClassSwitch( node, 0, variant, modules );
1354 //        } else {
1355 //            generateEnumSwitch( node, 0, variant );
1356 //        }
1357         unblock_nl();
1358     }
1359     
1360     public void visitNonVirtualParameterDecl( NonVirtualParameterDecl node )
1361     {
1362         txt( "${type} ${name}" );
1363     }
1364 
1365     public void visitVirtualParameterDecl( VirtualParameterDecl node )
1366     {
1367         txt( "${type} ${name}" );
1368     }
1369 
1370     public void visitCase( Case node )
1371     {
1372         // not used
1373         throw new UnsupportedOperationException();
1374     }
1375 
1376     public void visitCaseSignature( CaseSignature node )
1377     {
1378         // not used
1379         throw new UnsupportedOperationException();
1380     }
1381 
1382     public void visitParameter( Parameter node )
1383     {
1384         ParameterDecl paramDecl 
1385             =  ((OperationDecl)node.getParent().getParent().getParent())
1386               .getOptParameterDeclList( ((Integer)getVariable( "paramNum" )).intValue() );
1387         
1388         setVariable( "paramDecl", paramDecl );
1389         if( paramDecl instanceof NonVirtualParameterDecl )
1390         {
1391             txt( "${.paramDecl}" );
1392         } else if( paramDecl instanceof VirtualParameterDecl )
1393         {
1394             if( ((VirtualParameterDecl)paramDecl).getType().getType() instanceof ConstTypeDecl )
1395             {
1396                 txt( "${.paramDecl}" );
1397             } else {
1398                 txt( "${optType} ${name}" );
1399             }
1400         } else {
1401             throw new InternalError( paramDecl.getClass().getName() );
1402         }
1403     }
1404 }