From: jzhou Date: Tue, 15 Nov 2011 00:41:04 +0000 (+0000) Subject: Add a new feature for inner class: an anonymous inner class can now refer to the... X-Git-Url: http://plrg.eecs.uci.edu/git/?p=IRC.git;a=commitdiff_plain;h=d56ced93c269c5840dc396bc4d9faa02ffb3280b Add a new feature for inner class: an anonymous inner class can now refer to the local variables in its defintion context. The fix is not completely apply to Java specification in that we do not check if the local variables are final. According to the Java spec, only final variables can be referred to by the snonymous inner class --- diff --git a/Robust/src/IR/Tree/BuildIR.java b/Robust/src/IR/Tree/BuildIR.java index 6f3ed520..5d2b689b 100644 --- a/Robust/src/IR/Tree/BuildIR.java +++ b/Robust/src/IR/Tree/BuildIR.java @@ -375,7 +375,7 @@ public class BuildIR { md.getModifiers().addModifier(Modifiers.PUBLIC); md.getModifiers().addModifier(Modifiers.ABSTRACT); try { - BlockNode bn=parseBlock(bodyn); + BlockNode bn=parseBlock(cn, bodyn); cn.addMethod(md); state.addTreeCode(md,bn); } catch (Exception e) { @@ -392,7 +392,7 @@ public class BuildIR { public TaskDescriptor parseTaskDecl(ParseNode pn) { TaskDescriptor td=new TaskDescriptor(pn.getChild("name").getTerminal()); ParseNode bodyn=pn.getChild("body"); - BlockNode bn=parseBlock(bodyn); + BlockNode bn=parseBlock(null, bodyn); parseParameterList(td, pn); state.addTreeCode(td,bn); if (pn.getChild("flag_effects_list")!=null) @@ -969,7 +969,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) ExpressionNode en=null; if (epn!=null) { - en=parseExpression(epn.getFirstChild()); + en=parseExpression(cn, epn.getFirstChild()); en.setNumLine(epn.getFirstChild().getLine()); if(m.isStatic()) { // for static field, the initializer should be considered as a @@ -1025,11 +1025,11 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) int innerCount=0; - private ExpressionNode parseExpression(ParseNode pn) { + private ExpressionNode parseExpression(ClassDescriptor cn, 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); + return parseAssignmentExpression(cn, pn); } else if (isNode(pn,"logical_or")||isNode(pn,"logical_and")|| isNode(pn,"bitwise_or")||isNode(pn,"bitwise_xor")|| @@ -1045,7 +1045,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) ParseNode left=pnv.elementAt(0); ParseNode right=pnv.elementAt(1); Operation op=new Operation(pn.getLabel()); - OpNode on=new OpNode(parseExpression(left),parseExpression(right),op); + OpNode on=new OpNode(parseExpression(cn, left),parseExpression(cn, right),op); on.setNumLine(pn.getLine()); return on; } else if (isNode(pn,"unaryplus")|| @@ -1054,14 +1054,14 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) isNode(pn,"comp")) { ParseNode left=pn.getFirstChild(); Operation op=new Operation(pn.getLabel()); - OpNode on=new OpNode(parseExpression(left),op); + OpNode on=new OpNode(parseExpression(cn, left),op); on.setNumLine(pn.getLine()); return on; } else if (isNode(pn,"postinc")|| isNode(pn,"postdec")) { ParseNode left=pn.getFirstChild(); AssignOperation op=new AssignOperation(pn.getLabel()); - AssignmentNode an=new AssignmentNode(parseExpression(left),null,op); + AssignmentNode an=new AssignmentNode(parseExpression(cn, left),null,op); an.setNumLine(pn.getLine()); return an; @@ -1069,7 +1069,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) isNode(pn,"predec")) { ParseNode left=pn.getFirstChild(); AssignOperation op=isNode(pn,"preinc")?new AssignOperation(AssignOperation.PLUSEQ):new AssignOperation(AssignOperation.MINUSEQ); - AssignmentNode an=new AssignmentNode(parseExpression(left), + AssignmentNode an=new AssignmentNode(parseExpression(cn, left), new LiteralNode("integer",new Integer(1)),op); an.setNumLine(pn.getLine()); return an; @@ -1083,7 +1083,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) } else if (isNode(pn, "createobject")) { TypeDescriptor td = parseTypeDescriptor(pn); - Vector args = parseArgumentList(pn); + Vector args = parseArgumentList(cn, pn); boolean isglobal = pn.getChild("global") != null || pn.getChild("scratch") != null; String disjointId = null; if (pn.getChild("disjoint") != null) { @@ -1096,14 +1096,14 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) 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 ); + ExpressionNode en = parseExpression(cn, 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 ); + ExpressionNode en = parseExpression(cn, baseChild ); //System.out.println( "\nThe object passed has this expression " + en.printNode( 0 ) ); con.setSurroundingExpression( en ); } @@ -1124,8 +1124,6 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) return con; } else if (isNode(pn,"createobjectcls")) { - //TODO::: FIX BUG!!! static fields in caller context need to become parameters - //TODO::: caller context need to be passed in here TypeDescriptor td=parseTypeDescriptor(pn); innerCount++; ClassDescriptor cnnew=new ClassDescriptor(packageName,td.getSymbol()+"$"+innerCount, false); @@ -1133,10 +1131,30 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) cnnew.setImports(mandatoryImports, multiimports); cnnew.setSuper(td.getSymbol()); cnnew.setInline(); + // the inline anonymous class does not have modifiers, it cannot be static + // TODO: need to check the Java specification + cnnew.setModifiers(new Modifiers(Modifiers.PUBLIC)); + cnnew.setAsInnerClass(); + cnnew.setSurroundingClass(cn.getSymbol()); + cnnew.setSurrounding(cn); + cn.addInnerClass(cnnew); parseClassBody(cnnew, pn.getChild("decl").getChild("classbody")); + boolean hasConstructor = false; + for(Iterator method_it=cnnew.getMethods(); method_it.hasNext(); ) { + MethodDescriptor md=(MethodDescriptor)method_it.next(); + hasConstructor |= md.isConstructor(); + } + if((!hasConstructor) && (!cnnew.isEnum())) { + // add a default constructor for this class + MethodDescriptor md = new MethodDescriptor(new Modifiers(Modifiers.PUBLIC),cnnew.getSymbol(), false); + BlockNode bn=new BlockNode(); + state.addTreeCode(md,bn); + md.setDefaultConstructor(); + cnnew.addMethod(md); + } TypeDescriptor tdnew=state.getTypeDescriptor(cnnew.getSymbol()); - Vector args=parseArgumentList(pn); + Vector args=parseArgumentList(cn, pn); ParseNode idChild = pn.getChild( "id" ); ParseNode baseChild = pn.getChild( "base" ); //System.out.println("\n to print idchild and basechild for "); @@ -1166,7 +1184,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) disjointId = pn.getChild("disjoint").getTerminal(); } TypeDescriptor td=parseTypeDescriptor(pn); - Vector args=parseDimExprs(pn); + Vector args=parseDimExprs(cn, pn); int num=0; if (pn.getChild("dims_opt").getLiteral()!=null) num=((Integer)pn.getChild("dims_opt").getLiteral()).intValue(); @@ -1189,7 +1207,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) CreateObjectNode con=new CreateObjectNode(td, false, null); con.setNumLine(pn.getLine()); ParseNode ipn = pn.getChild("initializer"); - Vector initializers=parseVariableInitializerList(ipn); + Vector initializers=parseVariableInitializerList(cn, ipn); ArrayInitializerNode ain = new ArrayInitializerNode(initializers); ain.setNumLine(pn.getLine()); con.addArrayInitializer(ain); @@ -1219,7 +1237,7 @@ private void addOuterClassReferences( ClassDescriptor cn, int depth ) return new OpNode(nn,null,new Operation(Operation.ISAVAILABLE)); } else if (isNode(pn,"methodinvoke1")) { NameDescriptor nd=parseName(pn.getChild("name")); - Vector args=parseArgumentList(pn); + Vector args=parseArgumentList(cn, pn); MethodInvokeNode min=new MethodInvokeNode(nd); min.setNumLine(pn.getLine()); for(int i=0; i=INIT) { - /*if (cd.isInnerClass()) { - Modifiers fdmodifiers=new Modifiers(); - FieldDescriptor enclosingfd=new FieldDescriptor(fdmodifiers,new TypeDescriptor(cd.getSurroundingDesc()),"this___enclosing",null,false); - cd.addField(enclosingfd); - }*/ - /* Check to see that fields are well typed */ for(Iterator field_it=cd.getFields(); field_it.hasNext(); ) { FieldDescriptor fd=(FieldDescriptor)field_it.next(); @@ -143,10 +137,30 @@ public class SemanticCheck { } else { ClassDescriptor cd = (ClassDescriptor) obj; toanalyze.remove(cd); - - // need to initialize typeutil object here...only place we can - // get class descriptors without first calling getclass - getClass(cd, cd.getSymbol()); + if(cd.getInline()) { + getClass(cd, cd.getSymbol()); + // for inline defined anonymous classes, we need to check its + // surrounding class first to get its surrounding context + ClassDescriptor surroundingcd = cd.getSurroundingDesc(); + if(toanalyze.contains(surroundingcd)) { + toanalyze.remove(surroundingcd); + getClass(surroundingcd, surroundingcd.getSymbol()); + for (Iterator method_it = surroundingcd.getMethods(); method_it.hasNext(); ) { + MethodDescriptor md = (MethodDescriptor) method_it.next(); + try { + checkMethodBody(surroundingcd, md); + } catch (Error e) { + System.out.println("Error in " + md); + throw e; + } + } + } + } else { + // need to initialize typeutil object here...only place we can + // get class descriptors without first calling getclass + getClass(cd, cd.getSymbol()); + } + for (Iterator method_it = cd.getMethods(); method_it.hasNext(); ) { MethodDescriptor md = (MethodDescriptor) method_it.next(); try { @@ -745,31 +759,6 @@ public class SemanticCheck { } throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md); } - /*if (fd==null) { - ClassDescriptor surroundingCls=ltd.getClassDesc().getSurroundingDesc(); - int numencloses=1; - while(surroundingCls!=null) { - fd=(FieldDescriptor)surroundingCls.getFieldTable().get(fieldname); - if (fd!=null) { - surroundingCls=ltd.getClassDesc().getSurroundingDesc(); - FieldAccessNode ftmp=fan; - for(;numencloses>0;numencloses--) { - FieldAccessNode fnew=new FieldAccessNode(ftmp.left, "this___enclosing"); - fnew.setField((FieldDescriptor)surroundingCls.getFieldTable().get("this___enclosing")); - ftmp.left=fnew; - ftmp=fnew; - surroundingCls=surroundingCls.getSurroundingDesc(); - } - break; - } - surroundingCls=surroundingCls.getSurroundingDesc(); - numencloses++; - } - - if (fd==null) - throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md); - }*/ - if (fd.getType().iswrapper()) { FieldAccessNode fan2=new FieldAccessNode(left, fieldname); @@ -924,7 +913,7 @@ public class SemanticCheck { nn.setExpression(( ExpressionNode )theFieldNode); checkExpressionNode(md,nametable,( ExpressionNode )theFieldNode,td); return; - } + } } if((md instanceof MethodDescriptor) && ((MethodDescriptor)md).isStaticBlock()) { // this is a static block, all the accessed fields should be static field @@ -976,6 +965,7 @@ public class SemanticCheck { } } } + if (d instanceof VarDescriptor) { nn.setVar(d); } else if (d instanceof FieldDescriptor) { @@ -1186,6 +1176,37 @@ public class SemanticCheck { } //System.out.println( " the modified createObjectNode is " + con.printNode( 0 ) + "\n" ); } + + // add all the vars in the surrounding context of the inline class into the inline + // classes field table and pass them to the inline class' constructors + // TODO: BUGFIX. There need not add all the local vars of the surrounding context + // into the inline class. Should only add those that are referred to inside the inline + // class. Also these local vars should be final. But currently we've lost those + // information, so we cannot have that checked. + void InlineClassAddParamToCtor(MethodDescriptor md, ClassDescriptor cd , SymbolTable nametable, CreateObjectNode con, TypeDescriptor td ) { + Iterator it_values = nametable.getAllValueSet().iterator(); + while(it_values.hasNext()) { + Descriptor d = (Descriptor)it_values.next(); + if(d instanceof VarDescriptor && !d.getSymbol().equals("this")) { + con.addArgument(new NameNode(new NameDescriptor(d.getSymbol()))); + cd.addField(new FieldDescriptor(new Modifiers(Modifiers.PUBLIC), ((VarDescriptor)d).getType(), d.getSymbol(), null, false)); + for(Iterator it_methods = cd.getMethods(); it_methods.hasNext();) { + MethodDescriptor imd = (MethodDescriptor)it_methods.next(); + if(imd.isConstructor()) { + imd.addParameter(((VarDescriptor)d).getType(), d.getSymbol()+"_p"); + // add the initialize statement into this constructor + BlockNode obn = state.getMethodBody(imd); + NameNode nn=new NameNode(new NameDescriptor(d.getSymbol())); + NameNode fn = new NameNode (new NameDescriptor(d.getSymbol()+"_p")); + AssignmentNode an=new AssignmentNode(nn,fn,new AssignOperation(1)); + obn.addFirstBlockStatement(new BlockExpressionNode(an)); + state.addTreeCode(imd, obn); + } + } + } + } + } + void checkCreateObjectNode(Descriptor md, SymbolTable nametable, CreateObjectNode con, TypeDescriptor td) { TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()]; @@ -1244,6 +1265,11 @@ public class SemanticCheck { checkClass(classtolookin, INIT); if( classtolookin.isInnerClass() ) { InnerClassAddParamToCtor( (MethodDescriptor)md, ((MethodDescriptor)md).getClassDesc() , nametable, con, td ); + if(classtolookin.getInline()) { + // for an inline anonymous inner class, all the local variables are passed as + // parameters of the constructors of the inline class + InlineClassAddParamToCtor( (MethodDescriptor)md, classtolookin, nametable, con, td ); + } tdarray = new TypeDescriptor[con.numArgs()]; for (int i = 0; i < con.numArgs(); i++) { ExpressionNode en = con.getArg(i); diff --git a/Robust/src/Tests/DoTests b/Robust/src/Tests/DoTests index bddaa4ee..687668f1 100755 --- a/Robust/src/Tests/DoTests +++ b/Robust/src/Tests/DoTests @@ -24,4 +24,4 @@ dotest StaticInnerClassTest StaticInnerClassTest.java dotest StaticTest StaticTest.java dotest SwitchCaseTest SwitchCaseTest.java dotest TryCatchTest TryCatchTest.java -#dotest inner inner.java innerp.java innerpt.java innerCallback.java +dotest inner inner.java innerp.java innerpt.java innerCallback.java diff --git a/Robust/src/Tests/output/inner.output.goal b/Robust/src/Tests/output/inner.output.goal index 31735e74..79d81794 100644 --- a/Robust/src/Tests/output/inner.output.goal +++ b/Robust/src/Tests/output/inner.output.goal @@ -10,3 +10,4 @@ Outer class print: 35; 0 3 4 Outer class print: 35; 3 +innerCallback: 100