Make the compiler to support super.X/L.super.X which access super class' fields....
[IRC.git] / Robust / src / IR / Tree / BuildIR.java
index 5727965819d1e9dc3b1bad836d7370100a8a926a..6f3ed520c4f21eb96f52667005807ab026bb9654 100644 (file)
@@ -5,15 +5,17 @@ import Util.Pair;
 
 import java.io.File;
 import java.util.*;
-
+import java.io.*;
+import java.lang.Throwable;
 public class BuildIR {
   State state;
-
+  private boolean isRunningRecursiveInnerClass;
   private int m_taskexitnum;
 
   public BuildIR(State state) {
     this.state=state;
     this.m_taskexitnum = 0;
+    this.isRunningRecursiveInnerClass = false;
   }
 
   public void buildtree(ParseNode pn, Set toanalyze, String sourcefile) {
@@ -588,16 +590,109 @@ public class BuildIR {
       md.setDefaultConstructor();
       cn.addMethod(md);
     }
+
+
     popChainMaps();
 
     cn.setSourceFileName(currsourcefile);
+
+
+    
     if (analyzeset != null)
       analyzeset.add(cn);
     state.addClass(cn);
-
+//create this$n representing a final reference to the next surrounding class. each inner class should have whatever inner class
+//pointers the surrounding class has + a pointer to the surrounding class.
+   if( true )
+   {
+       this.isRunningRecursiveInnerClass = true; //fOR dEBUGGING PURPOSES IN ORDER TO DUMP STRINGS WHILE IN THIS CODE PATH
+       addOuterClassReferences( cn, 0 );
+       addOuterClassParam( cn, 0 );
+       this.isRunningRecursiveInnerClass = false;
+    }
     return cn;
   }
 
+private void initializeOuterMember( MethodDescriptor md, String fieldName, String formalParameter ) {
+        BlockNode obn = state.getMethodBody(md);
+         NameNode nn=new NameNode( new NameDescriptor( fieldName ) );
+        NameNode fn = new NameNode ( new NameDescriptor( formalParameter ) );
+          //nn.setNumLine(en.getNumLine())
+         AssignmentNode an=new AssignmentNode(nn,fn,new AssignOperation(1));
+         //an.setNumLine(pn.getLine());
+         obn.addFirstBlockStatement(new BlockExpressionNode(an));
+       // System.out.print( "The code inserted is : " + obn.printNode( 0 ) + "\n" );
+         state.addTreeCode(md, obn);
+}
+
+private void addOuterClassParam( ClassDescriptor cn, int depth )
+{
+       Iterator nullCheckItr = cn.getInnerClasses();
+       if( false == nullCheckItr.hasNext() )
+               return;
+
+       //create a typedescriptor of type cn
+       TypeDescriptor theTypeDesc = new TypeDescriptor( cn );
+       
+       for(Iterator it=cn.getInnerClasses(); it.hasNext(); ) {
+               ClassDescriptor icd=(ClassDescriptor)it.next();
+               if(icd.isStatic()) {
+                   continue;
+               }
+               
+               //iterate over all ctors of I.Cs and add a new param
+               for(Iterator method_it=icd.getMethods(); method_it.hasNext(); ) {
+                        MethodDescriptor md=(MethodDescriptor)method_it.next();
+                        if( md.isConstructor() ){
+                               md.addParameter( theTypeDesc, "surrounding$" + String.valueOf(depth) ); 
+                               initializeOuterMember( md, "this$" + String.valueOf( depth ), "surrounding$" + String.valueOf(depth) );
+                               //System.out.println( "The added param is " + md.toString() + "\n" );           
+                       }
+               }
+               addOuterClassParam( icd, depth + 1 );
+               
+       }
+       
+}
+private void addOuterClassReferences( ClassDescriptor cn, int depth )
+{
+       //SYMBOLTABLE does not have a length or empty method, hence could not define a hasInnerClasses method in classDescriptor
+       Iterator nullCheckItr = cn.getInnerClasses();
+       if( false == nullCheckItr.hasNext() )
+               return;
+
+       String tempCopy = cn.getClassName();
+       //MESSY HACK FOLLOWS
+       int i = 0;
+
+       ParseNode theNode = new ParseNode( "field_declaration" );
+       theNode.addChild("modifier").addChild( new ParseNode( "modifier_list" ) ).addChild("final");
+       ParseNode theTypeNode = new ParseNode("type");
+       ParseNode tempChildNode = theTypeNode.addChild("class").addChild( "name" );
+               //tempChildNode.addChild("base").addChild( new ParseNode("empty") );
+       tempChildNode.addChild("identifier").addChild ( tempCopy );
+       theNode.addChild("type").addChild( theTypeNode );
+       ParseNode variableDeclaratorID = new ParseNode("single");
+       String theStr = "this$" + String.valueOf( depth );
+       variableDeclaratorID.addChild( theStr );
+       ParseNode variableDeclarator = new ParseNode( "variable_declarator" );
+       variableDeclarator.addChild( variableDeclaratorID );
+       ParseNode variableDeclaratorList = new ParseNode("variable_declarators_list");
+       variableDeclaratorList.addChild( variableDeclarator );
+       theNode.addChild("variables").addChild( variableDeclaratorList );
+
+       for(Iterator it=cn.getInnerClasses(); it.hasNext(); ) {
+               ClassDescriptor icd=(ClassDescriptor)it.next();
+               parseFieldDecl( icd, theNode );         
+               /*if( true ) {
+                       SymbolTable fieldTable = icd.getFieldTable();
+                       //System.out.println( fieldTable.toString() );
+               }*/
+               icd.setInnerDepth( depth + 1 );
+               addOuterClassReferences( icd, depth + 1 );      
+       }
+}
+
   private void parseClassBody(ClassDescriptor cn, ParseNode pn) {
     ParseNode decls=pn.getChild("class_body_declaration_list");
     if (decls!=null) {
@@ -619,6 +714,7 @@ public class BuildIR {
   private void parseClassMember(ClassDescriptor cn, ParseNode pn) {
     ParseNode fieldnode=pn.getChild("field");
     if (fieldnode!=null) {
+      //System.out.println( pn.PPrint( 0, true ) );
       parseFieldDecl(cn,fieldnode.getChild("field_declaration"));
       return;
     }
@@ -657,6 +753,8 @@ public class BuildIR {
     throw new Error();
   }
 
+//10/9/2011 changed this function to enable creation of default constructor for inner classes.
+//the change was refactoring this function with the corresponding version for normal classes. sganapat
   private ClassDescriptor parseInnerClassDecl(ClassDescriptor cn, ParseNode pn) {
     String basename=pn.getChild("name").getTerminal();
     String classname=cn.getClassName()+"$"+basename;
@@ -669,11 +767,11 @@ public class BuildIR {
     ClassDescriptor icn=new ClassDescriptor(cn.getPackage(), classname, false);
     pushChainMaps();
     icn.setImports(mandatoryImports, multiimports);
-    icn.setAsInnerClass();
     icn.setSurroundingClass(cn.getSymbol());
     icn.setSurrounding(cn);
     cn.addInnerClass(icn);
-    if (!isEmpty(pn.getChild("super").getTerminal())) {
+
+     if (!isEmpty(pn.getChild("super").getTerminal())) {
       /* parse superclass name */
       ParseNode snn=pn.getChild("super").getChild("type").getChild("class").getChild("name");
       NameDescriptor nd=parseClassName(snn);
@@ -698,9 +796,29 @@ public class BuildIR {
     }
     icn.setModifiers(parseModifiersList(pn.getChild("modifiers")));
 
+   if (!icn.isStatic())
+     icn.setAsInnerClass();
+
     parseClassBody(icn, pn.getChild("classbody"));
+
+    boolean hasConstructor = false;
+    for(Iterator method_it=icn.getMethods(); method_it.hasNext(); ) {
+      MethodDescriptor md=(MethodDescriptor)method_it.next();
+      hasConstructor |= md.isConstructor();
+    }
+//sganapat adding change to allow proper construction of inner class objects
+    if((!hasConstructor) && (!icn.isEnum())) {
+      // add a default constructor for this class
+      MethodDescriptor md = new MethodDescriptor(new Modifiers(Modifiers.PUBLIC),
+                                                 icn.getSymbol(), false);
+      BlockNode bn=new BlockNode();
+      state.addTreeCode(md,bn);
+      md.setDefaultConstructor();
+      icn.addMethod(md);
+   }
     popChainMaps();
-    if (analyzeset != null)
+
+     if (analyzeset != null)
       analyzeset.add(icn);
     icn.setSourceFileName(currsourcefile);
     state.addClass(icn);
@@ -747,6 +865,8 @@ public class BuildIR {
   //we do not want to apply our resolveName function (i.e. deal with imports)
   //otherwise, if base == null, we do just want to resolve name.
   private NameDescriptor parseClassName(ParseNode nn) {
+    
+
     ParseNode base=nn.getChild("base");
     ParseNode id=nn.getChild("identifier");
     String classname = id.getTerminal();
@@ -834,6 +954,11 @@ public class BuildIR {
       ParseNode vardecl=pnv.elementAt(i);
       ParseNode tmp=vardecl;
       TypeDescriptor arrayt=t;
+       if( this.isRunningRecursiveInnerClass && false )
+       {       
+               System.out.println( "the length of the list is " + String.valueOf( pnv.size() ) );
+               System.out.println( "\n the parse node is \n" + tmp.PPrint( 0, true ) );
+       }
       while (tmp.getChild("single")==null) {
         arrayt=arrayt.makeArray(state);
         tmp=tmp.getChild("array");
@@ -842,6 +967,7 @@ public class BuildIR {
       ParseNode epn=vardecl.getChild("initializer");
 
       ExpressionNode en=null;
+      
       if (epn!=null) {
         en=parseExpression(epn.getFirstChild());
         en.setNumLine(epn.getFirstChild().getLine());
@@ -901,7 +1027,10 @@ public class BuildIR {
 
   private ExpressionNode parseExpression(ParseNode pn) {
     if (isNode(pn,"assignment"))
+       {
+          //System.out.println( "parsing a field decl in my class that has assignment in initialization " + pn.PPrint( 0, true ) + "\n");
       return parseAssignmentExpression(pn);
+       }
     else if (isNode(pn,"logical_or")||isNode(pn,"logical_and")||
              isNode(pn,"bitwise_or")||isNode(pn,"bitwise_xor")||
              isNode(pn,"bitwise_and")||isNode(pn,"equal")||
@@ -960,7 +1089,24 @@ public class BuildIR {
       if (pn.getChild("disjoint") != null) {
         disjointId = pn.getChild("disjoint").getTerminal();
       }
+      ParseNode idChild = (pn.getChild( "id" ));
+      ParseNode baseChild = (pn.getChild( "base" ));
+      
       CreateObjectNode con = new CreateObjectNode(td, isglobal, disjointId);
+      if( null != idChild && null != idChild.getFirstChild() ) {
+       idChild = idChild.getFirstChild();
+       //System.out.println( "\nThe object passed has this expression " + idChild.PPrint( 0, true ) );
+       ExpressionNode en = parseExpression( idChild ); 
+       //System.out.println( "\nThe object passed has this expression " + en.printNode( 0 ) );
+       con.setSurroundingExpression( en );
+      }
+      else if( null != baseChild  && null != baseChild.getFirstChild()  ) {
+       baseChild = baseChild.getFirstChild();
+       //System.out.println( "\nThe object passed has this expression " + baseChild.PPrint( 0, true ) );
+       ExpressionNode en = parseExpression( baseChild ); 
+       //System.out.println( "\nThe object passed has this expression " + en.printNode( 0 ) );
+       con.setSurroundingExpression( en );     
+      }
       con.setNumLine(pn.getLine());
       for (int i = 0; i < args.size(); i++) {
         con.addArgument((ExpressionNode) args.get(i));
@@ -991,7 +1137,13 @@ public class BuildIR {
       TypeDescriptor tdnew=state.getTypeDescriptor(cnnew.getSymbol());
 
       Vector args=parseArgumentList(pn);
-
+      ParseNode idChild = pn.getChild( "id" );
+      ParseNode baseChild = pn.getChild( "base" );
+      //System.out.println("\n to print idchild and basechild for ");
+      /*if( null != idChild )
+       System.out.println( "\n trying to create an inner class and the id child passed is "  + idChild.PPrint( 0, true ) );
+      if( null != baseChild )
+       System.out.println( "\n trying to create an inner class and the base child passed is "  + baseChild.PPrint( 0, true ) );*/
       CreateObjectNode con=new CreateObjectNode(tdnew, false, null);
       con.setNumLine(pn.getLine());
       for(int i=0; i<args.size(); i++) {
@@ -1053,11 +1205,11 @@ public class BuildIR {
       nn.setNumLine(pn.getLine());
       return nn;
     } else if (isNode(pn,"parentclass")) {
-      NameDescriptor nd=new NameDescriptor("this");
+      NameDescriptor nd=new NameDescriptor(pn.getChild("name").getFirstChild().getFirstChild().getTerminal());
       NameNode nn=new NameNode(nd);
       nn.setNumLine(pn.getLine());
-
-      FieldAccessNode fan=new FieldAccessNode(nn,"this$parent");
+       //because inner classes pass right thru......
+      FieldAccessNode fan=new FieldAccessNode(nn,"this");
       fan.setNumLine(pn.getLine());
       return fan;
     } else if (isNode(pn,"isavailable")) {
@@ -1091,6 +1243,22 @@ public class BuildIR {
       FieldAccessNode fan=new FieldAccessNode(en,fieldname);
       fan.setNumLine(pn.getLine());
       return fan;
+    } else if (isNode(pn,"superfieldaccess")) {
+       ExpressionNode en=new NameNode(new NameDescriptor("super"));
+       String fieldname=pn.getChild("field").getTerminal();
+
+       FieldAccessNode fan=new FieldAccessNode(en,fieldname);
+       fan.setNumLine(pn.getLine());
+       return fan;
+    } else if (isNode(pn,"supernamefieldaccess")) {
+       ExpressionNode en=parseExpression(pn.getChild("base").getFirstChild());
+       ExpressionNode exp = new FieldAccessNode(en, "super");
+       exp.setNumLine(pn.getLine());
+       String fieldname=pn.getChild("field").getTerminal();
+
+       FieldAccessNode fan=new FieldAccessNode(exp,fieldname);
+       fan.setNumLine(pn.getLine());
+       return fan;
     } else if (isNode(pn,"arrayaccess")) {
       ExpressionNode en=parseExpression(pn.getChild("base").getFirstChild());
       ExpressionNode index=parseExpression(pn.getChild("index").getFirstChild());