import java.util.*;
import Jakarta.util.*;
import java.io.*;
public class program {
// has file already been formatted for mixin composition?
public boolean alreadyPrepared( JTSParseTree t ) {
// arg[2].arg[0] is the optionally specified AST_Class declaration
AST_Class ac = ( AST_Class ) arg[2].arg[0];
if ( ac == null ) {
AstNode.error( "file has no base or refinement declaration" );
return true;
}
return ac.alreadyPrepared( t );
}
// updates firstType, lastType data members of JTSParseTree given
// TypeDeclaration r
private void updateTypes( JTSParseTree t, TypeDeclaration r ) {
if ( t.firstType == null )
t.firstType = r;
t.lastType = r;
}
private void initTypes( JTSParseTree t ) {
t.firstType = null;
t.lastType = null;
}
// this method is called if it has already been prepared -- this
// is possible only if mixin was used to compose a set of layers
// previously.
public void processAlreadyPrepared( JTSParseTree t ) {
// the primary objective of this method is to set the firstType
// and lastType values of t. As a secondary objective, we do
// some simple error checking.
// Step 1: iterate through the AST_Class list. This list must
// be an alternating set of SoUrCe and ModTypeDecl
// declarations. Along the way, update firstType, lastType.
AstCursor k = new AstCursor();
AST_Class sd = ( AST_Class ) arg[2].arg[0];
for ( k.FirstElement( sd ); k.MoreElement(); k.NextElement() ) {
if ( k.node instanceof SourceDecl ) {
// now extract the name of the layer (aspect) so that we can
// tag each of its AST nodes with the appropriate name
String lName = ( ( AST_QualifiedName ) k.node.arg[0] ).GetName();
k.NextElement();
updateTypes( t, ( TypeDeclaration ) k.node );
k.node.setSource( lName );
}
else
AstNode.error( "file was incorrectly created/composed" );
}
}
// prepare file for mixin composition
// this amounts to introduceing SoUrCe declarations and
// rewriting the TypeDeclaration extensions into its java equivalent
public void prepare( JTSParseTree t ) {
AST_Class sd;
TypeDeclaration repl;
// Step 1: first check to see if the parsed file is already
// prepared. We will know this if "SoUrCe" nodes exist.
initTypes( t );
if ( alreadyPrepared( t ) ) {
processAlreadyPrepared( t );
return;
}
// Step 2: so the file needs to be prepared. This means that
// there is one TypeDeclaration. We need to place a
// SoUrCe statement in front of it, and convert it
// into a normal class, interface, etc. declaration.
// along the way, remember the first and last type
// declarations on the list. Doing so is useful as
// we will need these references later to do mixin
// parameter substitution
AstCursor k = new AstCursor();
int count = 0;
sd = ( AST_Class ) arg[2].arg[0];
for ( k.FirstElement( sd ); k.MoreElement(); k.NextElement() ) {
// Step 2.1: keep a count of the number of type declarations.
// also, generate a relative URI for the universal
// to increase portability of source filename.
count++;
String universalName = Main.file2uri( t.filepath ) ;
// Step 2.2: before we proceed, make sure that the element
// we are examining is indeed a ModTypeDecl. If not,
// the .jak file is in the wrong format.
if ( ! ( k.node instanceof ModTypeDecl ) )
AstNode.fatalError( k.node.findToken(), ".jak file has incorrect format: " +
"expected a modified type declaration (ModTypeDecl) but found " +
k.node.getClass().getName() );
// Step 2.3: is the type declaration an extension or not?
String isRoot = "";
if ( ! ( ( ModTypeDecl ) k.node ).isExtension() )
isRoot = "RooT";
// Step 2.4 form the SoUrCe declaration
sd = AST_Class.MakeAST( "\n\nSoUrCe " + isRoot + " " +
getSource() + " " +
"\"" + universalName + "\";" );
k.AddBefore( sd );
repl = ( ( TypeDeclaration ) k.node ).prepareReplace( t );
// Step 2.5: now remember the first and last type declaration.
// this information is critical for instantiating
// mixin layer parameters
updateTypes( t, repl );
}
// Step 3: if there is more than one type declaration, it's an error
if ( count==0 )
AstNode.error( "file has no base or refinement declaration" );
else
if ( count >1 )
AstNode.error( "file has 2 or more root or refinement declarations" );
}
// compose base tree with extension tree
public void compose( AstNode etree, JTSParseTree base,
JTSParseTree ext ) {
// composition involves
// (a) doing nothing about aspect declaration
// (b) compose the imports lists
// (c) compose the AST_Class declarations
// Step 1: do preliminary testing
// make sure argument is correct type
program e = ( program ) etree;
// Step 2: compose the imports list and AST_Class declarations
arg[1].compose( e.arg[1], base, ext );
arg[2].compose( e.arg[2], base, ext );
/*
// Step 3: add a blank line to separate imports and packages
if (arg[1].arg[0] != null)
arg[1].arg[0].prependComment("\n");
*/
}
// can remove into its own layer -- stolen from preprocess
public boolean isExtension() {
if ( arg[2].arg[0] == null )
// missing TypeDeclaration
AstNode.fatalError( "file has no base or refinement declaration" );
return ( ( AST_Class ) arg[2].arg[0] ).isExtension();
}
}