The compiler is BROKEN, but it's NOT MY FAULT. I think Brian forgot to check in somet...
authorstephey <stephey>
Thu, 21 Apr 2011 09:15:39 +0000 (09:15 +0000)
committerstephey <stephey>
Thu, 21 Apr 2011 09:15:39 +0000 (09:15 +0000)
KNOWN PROBLEM: The package declarations can go only 1 level deep.. this means that imports would only work 1 level deep as well (but the logic for it is all correct). I think the problem lies in the .cup file... When I get the name of a package, I only get the last thing in the list of something.something.something.last.class when I ask for the package. I'll check it out later.

Robust/src/IR/ClassDescriptor.java
Robust/src/IR/Tree/BuildIR.java
Robust/src/IR/Tree/SemanticCheck.java
Robust/src/IR/TypeUtil.java

index 46d73e764737fff8d69eee7940bc23cf33be8118..c8e1c9d2620b761495679187b174af8f94e7fccb 100644 (file)
@@ -19,7 +19,6 @@ public class ClassDescriptor extends Descriptor {
   SymbolTable methods;
   
   Hashtable singleImports;
-  Vector multiImports;
   
   int numstaticblocks = 0;
   int numstaticfields = 0;
@@ -413,9 +412,8 @@ public class ClassDescriptor extends Descriptor {
     this.sourceFileName=sourceFileName;
   }
   
-  public void setImports(Hashtable singleImports, Vector multiImports) {
+  public void setImports(Hashtable singleImports) {
     this.singleImports = singleImports;
-    this.multiImports  = multiImports;
   }
   
   public String getSourceFileName(){
index 087415d05f41eb16c7b03a21e3e9b5587a48e47a..29ced9be558150be8d282834212728bfbe2213dc 100644 (file)
@@ -1,6 +1,8 @@
 package IR.Tree;
 import IR.*;
 import Util.Lattice;
+
+import java.io.File;
 import java.util.*;
 
 public class BuildIR {
@@ -27,36 +29,66 @@ public class BuildIR {
     }
   }
 
-  Hashtable singleimports;
-  Vector multiimports;
+  //This is all single imports and a subset of the
+  //multi imports that have been resolved. 
+  Hashtable mandatoryImports;
+  //maps class names in file to full name
+  //Note may map a name to an ERROR. 
+  Hashtable multiimports;
   NameDescriptor packages;
 
   /** Parse the classes in this file */
   public void parseFile(ParseNode pn, Set toanalyze, String sourcefile) {
-    singleimports=new Hashtable();
-    multiimports=new Vector();
-    ParseNode ipn=pn.getChild("imports").getChild("import_decls_list");
-    if (ipn!=null) {
-      ParseNodeVector pnv=ipn.getChildren();
-      for(int i=0; i<pnv.size(); i++) {
-       ParseNode pnimport=pnv.elementAt(i);
-       NameDescriptor nd=parseName(pnimport.getChild("name"));
-       // TODO need to implement
-       if (isNode(pnimport,"import_single"))
-         if(!singleimports.containsKey(nd.getIdentifier())) {
-           //map name to full name (includes package/directory
-           singleimports.put(nd.getIdentifier(), nd.getPathFromRootToHere(nd.getIdentifier()));
-         } else {
-           throw new Error("Error: class " + nd.getIdentifier() + " is already more than once in a single type import inside "+sourcefile);
-         }
-       else
-         //TODO MULTI-IMPORTS!
-         multiimports.add(nd);
+    mandatoryImports = new Hashtable();
+    multiimports = new Hashtable();
+    ParseNode ipn = pn.getChild("imports").getChild("import_decls_list");
+    if (ipn != null) {
+      ParseNodeVector pnv = ipn.getChildren();
+      for (int i = 0; i < pnv.size(); i++) {
+        ParseNode pnimport = pnv.elementAt(i);
+        NameDescriptor nd = parseNameRaw(pnimport.getChild("name"));
+        if (isNode(pnimport, "import_single"))
+          if (!mandatoryImports.containsKey(nd.getIdentifier())) {
+            // map name to full name (includes package/directory
+            mandatoryImports.put(nd.getIdentifier(), nd.getPathFromRootToHere(nd.getIdentifier()));
+          } else {
+            throw new Error("An ambiguous class "+ nd.getIdentifier() +" has been found. It is included for " +
+                       ((String)mandatoryImports.get(nd.getIdentifier())).replace("___________", ".") + " and " +
+                       nd.getPathFromRootToHere(nd.getIdentifier()).replace("___________", "."));
+          }
+        else {
+          // This kind of breaks away from tradition a little bit by doing the file checks here
+          // instead of in Semantic check, but doing it here is easier because we have a mapping early on
+          // if I wait until semantic check, I have to change ALL the type descriptors to match the new
+          // mapping and that's both ugly and tedious.
+          File folder = new File(nd.getPathFromRootToHere(nd.getIdentifier()).replace('.', '/'));
+          if (folder.exists()) {
+            for (String file : folder.list()) {
+              // if the file is of type *.java add to multiImport list.
+              if (file.lastIndexOf('.') != -1
+                  && file.substring(file.lastIndexOf('.')).equalsIgnoreCase(".java")) {
+                String classname = file.substring(0, file.length() - 5);
+                // single imports have precedence over multi-imports
+                if (!mandatoryImports.containsKey(classname)) {
+                  if (multiimports.containsKey(classname)) {
+                    // put error in for later, in case we try to import.
+                    multiimports.put(classname, new Error("Error: class " + nd.getIdentifier()
+                        + " is defined more than once in a multi-import in " + sourcefile));
+                  } else {
+                    multiimports.put(classname, nd.getIdentifier().replace("\\.", "___________")
+                        + "___________" + classname);
+                  }
+                }
+              }
+            }
+          } else {
+            throw new Error("Import package " + folder.getAbsolutePath() + " in  " + sourcefile
+                + " cannot be resolved.");
+          }
+        }
       }
     }
     
-    
-    
     ParseNode ppn=pn.getChild("packages").getChild("package");
     String packageName = null;
     if (ppn!=null) {
@@ -178,7 +210,7 @@ public class BuildIR {
   
   private ClassDescriptor parseEnumDecl(ClassDescriptor cn, ParseNode pn) {
     ClassDescriptor ecd=new ClassDescriptor(pn.getChild("name").getTerminal(), false);
-    ecd.setImports(singleimports, multiimports);
+    ecd.setImports(mandatoryImports);
     ecd.setAsEnum();
     if(cn != null) {
       ecd.setSurroundingClass(cn.getSymbol());
@@ -213,7 +245,7 @@ public class BuildIR {
   
   public ClassDescriptor parseInterfaceDecl(ParseNode pn) {
     ClassDescriptor cn=new ClassDescriptor(pn.getChild("name").getTerminal(), true);
-    cn.setImports(singleimports, multiimports);
+    cn.setImports(mandatoryImports);
     //cn.setAsInterface();
     if (!isEmpty(pn.getChild("superIF").getTerminal())) {
       /* parse inherited interface name */
@@ -412,7 +444,7 @@ public class BuildIR {
        System.out.println("OPTIONAL FOUND!!!!!!!");
       } else { optional = false;
               System.out.println("NOT OPTIONAL");}
-
+      
       TypeDescriptor type=parseTypeDescriptor(paramn);
 
       String paramname=paramn.getChild("single").getTerminal();
@@ -455,7 +487,7 @@ public class BuildIR {
       String newClassname = packageName + "___________" + pn.getChild("name").getTerminal();
       cn= new ClassDescriptor(packageName, newClassname.replaceAll("\\.", "___________") , false);
     }
-    cn.setImports(singleimports, multiimports);
+    cn.setImports(mandatoryImports);
     if (!isEmpty(pn.getChild("super").getTerminal())) {
       /* parse superclass name */
       ParseNode snn=pn.getChild("super").getChild("type").getChild("class").getChild("name");
@@ -589,7 +621,7 @@ public class BuildIR {
   
   private ClassDescriptor parseInnerClassDecl(ClassDescriptor cn, ParseNode pn) {
     ClassDescriptor icn=new ClassDescriptor(pn.getChild("name").getTerminal(), false);
-    icn.setImports(singleimports, multiimports);
+    icn.setImports(mandatoryImports);
     icn.setAsInnerClass();
     icn.setSurroundingClass(cn.getSymbol());
     icn.setSurrounding(cn);
@@ -664,12 +696,34 @@ public class BuildIR {
   private NameDescriptor parseName(ParseNode nn) {
     ParseNode base=nn.getChild("base");
     ParseNode id=nn.getChild("identifier");
-    //TODO check for bugs with naming things like classes...
-    String terminal = (String) (singleimports.containsKey(id.getTerminal())?singleimports.get(id.getTerminal()):id.getTerminal());
+    String classname = resolveName(id.getTerminal());
     if (base==null) {
-      return new NameDescriptor(terminal);
+      return new NameDescriptor(classname);
     }
-    return new NameDescriptor(parseName(base.getChild("name")),terminal);
+    return new NameDescriptor(parseName(base.getChild("name")),classname);
+  }
+  
+  //This will get the mapping of a terminal class name
+  //to a canonical classname (with imports/package locations in them)
+  private String resolveName(String terminal) {
+    if(mandatoryImports.containsKey(terminal)) {
+      return  (String) mandatoryImports.get(terminal);
+    } else {
+      if(multiimports.containsKey(terminal)) {
+        //Test for error
+        Object o = multiimports.get(terminal);
+        if(o instanceof Error) {
+          throw new Error("Class " + terminal + " is ambiguous. Cause: more than 1 package import contain the same class.");
+        } else {
+          //At this point, if we found a unique class
+          //we can treat it as a single, mandatory import.
+          mandatoryImports.put(terminal, o);
+          return (String) o;
+        }
+      }
+    }
+    
+    return terminal;
   }
   
   //only function difference between this and parseName() is that this
@@ -864,7 +918,7 @@ public class BuildIR {
       TypeDescriptor td=parseTypeDescriptor(pn);
       innerCount++;
       ClassDescriptor cnnew=new ClassDescriptor(td.getSymbol()+"$"+innerCount, false);
-      cnnew.setImports(singleimports, multiimports);
+      cnnew.setImports(mandatoryImports);
       cnnew.setSuper(td.getSymbol());
       parseClassBody(cnnew, pn.getChild("decl").getChild("classbody"));
       Vector args=parseArgumentList(pn);
index d123a172918e45c723c126a684dc710b2c031a69..a7238a89d6c4c8475b034a3fbba78cc4e36dbd27 100644 (file)
@@ -11,6 +11,9 @@ public class SemanticCheck {
   HashSet toanalyze;
   HashMap<ClassDescriptor, Integer> completed;
   
+  //This is the class mappings for a particular file based 
+  //on the import names. Maps class to canonical class name. 
+  static Hashtable singleImportMap;
   public static final int NOCHECK=0;
   public static final int REFERENCE=1;
   public static final int INIT=2;
@@ -37,7 +40,6 @@ public class SemanticCheck {
   public ClassDescriptor getClass(ClassDescriptor context, String classname) {
     return getClass(context, classname, INIT);
   }
-
   public ClassDescriptor getClass(ClassDescriptor context, String classname, int fullcheck) {
     if (context!=null) {
       Hashtable remaptable=context.getSingleImportMappings();
@@ -47,7 +49,7 @@ public class SemanticCheck {
     checkClass(cd, fullcheck);
     return cd;
   }
-
+  
   public void checkClass(ClassDescriptor cd) {
     checkClass(cd, INIT);
   }
@@ -121,6 +123,8 @@ public class SemanticCheck {
       } else {
         ClassDescriptor cd = (ClassDescriptor) obj;
         toanalyze.remove(cd);
+        //set the class mappings based on imports. 
+        singleImportMap = cd.getSingleImportMappings();
         
         // need to initialize typeutil object here...only place we can
         // get class descriptors without first calling getclass
index 35ee680beae586f142a95fcdb7f45f8af24f9bb6..05f93f5029bbafff321389e0b121364dfcbd131f 100644 (file)
@@ -28,6 +28,7 @@ public class TypeUtil {
   }
 
   public void addNewClass(String cl, Set todo) {
+    //search through the default locations for the file.
     for (int i = 0; i < state.classpath.size(); i++) {
       String path = (String) state.classpath.get(i);
       //The name has ___________ to separate out packages
@@ -41,7 +42,7 @@ public class TypeUtil {
           throw new Error(e);
         }
       }
-    }
+    }    
     throw new Error("Couldn't find class " + cl);
   }