AmbiguousName.java |
1 // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas 2 3 package jminusminus; 4 5 import java.util.StringTokenizer; 6 7 /** 8 * Ambiguous names are meant to deal with snippets like 9 * 10 * <pre> 11 * x.y.z 12 * a.b.c() 13 * </pre> 14 * 15 * Clearly, z is a field and c is a method. But what about x.y and a.b ? x could 16 * be a package name and y a type, making for a (static) class field selection. 17 * Or, x could be a local variable and y an instance field. The parser cannot 18 * know how to parse these. 19 * 20 * Disambiguating the ambiguity must wait until analysis time. The parser can, 21 * with x.y.z, treat the .z as a field selection, but constructs an 22 * AmbiguousName object encapsulating the x.y . And it can, with a.b.c(), treat 23 * the .c() as a message expression, but constructs an AbiguousName object 24 * encapsulating a.b. 25 * 26 * reclassify() is called upon in JFieldSelection.analyze() and 27 * JMessageExpression.analyze() to reclassify the components and construct the 28 * proper ast, following the rules for names in the Java language Specification 29 * (Third Edition), section 6.5.2. In j--, both x.y and a.b are clearly 30 * expressions in these contexts. If inner types were to be introduced, their 31 * meaning and their reclassification would necessarily be more complicated. 32 */ 33 34 class AmbiguousName { 35 36 /** 37 * Line in which the ambiguous name occurs in the source file. 38 */ 39 private int line; 40 41 /** The ambiguous part, eg x.y */ 42 private String name; 43 44 /** 45 * Construct an encapsulation of the ambiguous portion of a snippet like 46 * x.y.z. 47 * 48 * @param line 49 * line in which the ambiguous name occurs in the source file. 50 * @param name 51 * the ambiguous part. 52 */ 53 54 public AmbiguousName(int line, String name) { 55 this.line = line; 56 this.name = name; 57 } 58 59 /** 60 * Reclassify the name according to the rules in the Java Language 61 * Specification. 62 * 63 * @param context 64 * context in which we look up the component names. 65 * @return the properly parsed AST. 66 */ 67 68 public JExpression reclassify(Context context) { 69 // Easier because we require all types to be imported. 70 JExpression result = null; 71 StringTokenizer st = new StringTokenizer(name, "."); 72 73 // Firstly, find a variable or Type. 74 String newName = st.nextToken(); 75 IDefn iDefn = null; 76 77 do { 78 iDefn = context.lookup(newName); 79 if (iDefn != null) { 80 result = new JVariable(line, newName); 81 break; 82 } else if (!st.hasMoreTokens()) { 83 // Nothing found. :( 84 JAST.compilationUnit.reportSemanticError(line, 85 "Cannot find name " + newName); 86 return null; 87 } else { 88 newName += "." + st.nextToken(); 89 } 90 } while (true); 91 92 // For now we can assume everything else is fields. 93 while (st.hasMoreTokens()) { 94 result = new JFieldSelection(line, result, st.nextToken()); 95 } 96 return result; 97 } 98 99 } 100