import java.util.*;
import Jakarta.util.FixDosOutputStream;
import java.io.*;
public class UmodClassDecl {
// this method is called on parse tress of the SoUrCe file
// the idea is for this method to propagate the contents of
// this UmodClassDecl AST to the file referenced in the SoUrCe file.
public void propagateChanges() {
String myName = null;
String referencedName = null;
// Step 1: fetch the referenced file, parse it, and locate
// the lone ModTypeDecl declaration
UnMixinUtil u = new UnMixinUtil();
// Step 2: do some error checking. The ModTypeDecl must reference
// a UmodClassDecl or UmodClassExt with the same QName as
// our parse tree
// note u.location is of type ModTypeDecl, whose first
// argument is an UnmodifiedTypeDeclaration -- in our
// case, it should be a UmodClassDecl
if ( kernelConstants.globals().unmixin.base ) {
// testing for UmodClassDecl
if ( u.location.arg[1] instanceof UmodClassDecl ) {
referencedName = u.location.arg[1].arg[0].tok[0].tokenName();
myName = arg[0].tok[0].tokenName();
if ( !referencedName.equals( myName ) )
AstNode.fatalError( tok[0],
"expecting class " + myName + " but got "
+ referencedName +
" file " +
kernelConstants.globals().unmixin.fileName +
" not updated" );
}
else
AstNode.fatalError( tok[0],
"expecting UmodClassDecl but got " +
u.location.arg[1].getClass().getName() +
" file " +
kernelConstants.globals().unmixin.fileName +
" not updated" );
}
else {
// testing for UmodClassExt
if ( u.location.arg[1] instanceof Ute &&
u.location.arg[1].arg[0] instanceof UmodClassExt ) {
referencedName = u.location.arg[1].arg[0].arg[0].tok[0].tokenName();
myName = arg[0].tok[0].tokenName();
if ( !referencedName.equals( myName ) )
AstNode.fatalError( tok[0],
"expecting class extension" + myName +
" but got " + referencedName +
" file " +
kernelConstants.globals().unmixin.fileName +
" not updated" );
}
else
AstNode.fatalError( tok[0],
"expecting Ute (or rather UmodClassExt) but got " +
u.location.arg[1].getClass().getName() +
" file " +
kernelConstants.globals().unmixin.fileName +
" not updated" );
}
// Step 3: we're ready to make the changes!
// see if there is an extends clause -- there shouldn't
// be if a class appears to extend itself. (This is
// possible because of name mangling -- when names are
// unmangled, a class appears to extend itself).
ExtendsClause k = ( ExtendsClause ) arg[1].arg[0];
if ( k != null ) {
String xname = ( ( AST_QualifiedName ) arg[1].arg[0].arg[0] ).GetName();
if ( xname.equals( myName ) )
k = null;
}
boolean updated = false;
if ( kernelConstants.globals().unmixin.base )
updated = ( ( UmodClassDecl ) u.location.arg[1] ).
propagateChanges( k, ( ImplementsClause ) arg[2].arg[0],
( ClassBody ) arg[3] );
else
updated = ( ( UmodClassExt ) u.location.arg[1].arg[0] ).
propagateChanges( ( ImplementsClause ) arg[2].arg[0],
( ClassBody ) arg[3] );
// Step 4: last thing we do -- propagate the changes back to the file
if ( updated )
u.output();
}
// this method is called on the original AST, not the one with
// SoUrCe declarations
public boolean propagateChanges( ExtendsClause k,
ImplementsClause i,
ClassBody b ) {
// explicitly call to achieve side effects
boolean u = oneChange( arg[1],k );
u = oneChange( arg[2],i ) || u;
u = oneChange( arg[3],b ) || u;
return u;
}
public static boolean oneChange( AstNode old, AstNode nu ) {
boolean updated = false;
if ( nu == null ) {
if ( !old.toString().trim().equals( "" ) ) {
old.Delete();
updated = true;
}
}
else {
if ( nu!=null && ! ( old.toString().trim().equals( nu.toString().trim() ) ) ) {
old.Replace( nu );
updated = true;
}
}
return updated;
}
}