import java.util.*; import java.io.*; public class SmClassDecl { public Hashtable h = new Hashtable(); // piggyback onto checkForErrors the checking for // errors in replicated definitions within a single file. // the error checking is performed on State definitions // and Transition definitions public void checkForErrors( int state, String file ) { super.checkForErrors( state, file ); StatesList slb = ( StatesList ) arg[2].arg[0]; if ( slb!=null ) slb.add2Hash( h, kernelConstants.globals().currentFileName ); ESList esb = ( ESList ) arg[3].arg[0]; if ( esb!=null ) esb.add2Hash( h, kernelConstants.globals().currentFileName ); } public void compose( AstNode etree ) { // Step 0: Do some standard error checking - etree is of type // SmClassDecl. SmClassDecl e = ( SmClassDecl ) etree; // Step 1: compose the root clauses arg[0].compose( e.arg[0] ); // Step 2: compose and otherwise clauses. Just merge the lists arg[1].compose( e.arg[1] ); // Step 3: foreach key in the extension's hashtable, try to // add it to the base hash table. If there is a collision // then we have an error. for ( Enumeration c = e.h.keys(); c.hasMoreElements(); ) { String key = ( String ) c.nextElement(); String source = ( String ) e.h.get( key ); String result = ( String ) h.get( key ); if ( result==null ) h.put( key,source ); else // so there is a state already defined in base with 'key' as its name // if either the extension or base has correctly defined the // state, then don't issue a warning if ( ! ( result.equals( "unknown layer" ) || source.equals( "unknown layer" ) ) ) AstNode.error( key + " is defined both in " + source + " and in " + result ); } // Step 4: all that remains is to compose AST_FieldDecls. What's // unusual here is that not only do we compose the base and // extension AST_FieldDecls, but we also have to pass in // a LinkedList of ASTs of extension method bodies that // are not part of the extension AST_FieldDecl proper. // so ASTs like edge actions, edge boolean tests, exit // methods must first be harvested onto this list before // we can officially compose. The reason for doing so // is that these extra method bodies may reference methods // of the "base" class via the Base() construct. These // references must be rewritten. // The sources of harvest include the: OtherwiseClause, // and ESList. no class bodies are present in StatesLists LinkedList ll = new LinkedList(); OtherwiseClauses oc = ( OtherwiseClauses ) e.arg[1].arg[0]; if ( oc!=null ) oc.harvestAst( ll ); ESList es = ( ESList ) e.arg[3].arg[0]; if ( es!=null ) es.harvestAst( ll ); // Step 5: compose the methods and data members of AST_FieldDecl // in the approved manner arg[4].arg[0] = AST_FieldDecl.compose( arg[4].arg[0], e.arg[4].arg[0], ll ); // Step 6: the last step in composition is to assume that there // are no semantic errors and compose directly the // stateslist and eslist declarations arg[2].compose( e.arg[2] ); arg[3].compose( e.arg[3] ); } }