001    package org.mesopotamia.lang.java;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    import java.util.logging.Logger;
007    
008    import org.mesopotamia.LanguageElement;
009    import org.mesopotamia.MesopotamiaException;
010    import org.mesopotamia.MesopotamiaNode;
011    import org.mesopotamia.NodeData;
012    import org.mesopotamia.RepositoryLanguage;
013    import org.mesopotamia.Scan;
014    import org.mesopotamia.SourceUnit;
015    import org.mesopotamia.lang.java.TypeDefinition.ParameterMatch;
016    import org.mesopotamia.lang.java.ref.Info;
017    import org.mesopotamia.lang.java.ref.MethodInfo;
018    import org.mesopotamia.lang.java.ref.Reference;
019    import org.mesopotamia.lang.java.ref.Scope;
020    import org.mesopotamia.lang.java.ref.TypeInfo;
021    import org.mesopotamia.lang.java.ref.TypeSpecInfo;
022    import org.mesopotamia.lang.java.ref.VariableInfo;
023    import org.w3c.dom.Element;
024    
025    import biz.hammurapi.util.CollectionVisitable;
026    import biz.hammurapi.util.Visitor;
027    
028    @SuppressWarnings("unchecked")
029    public class NewExpression extends PrimaryExpression implements TypeDefinitionOrAnonymous, Reference<MethodInfo> {
030            private static final Logger logger = Logger.getLogger(NewExpression.class.getName());
031    
032            private Type specType;
033            private int dimensions;
034            
035            private List<ArrayInitializer> ArrayInitializers;
036    
037            public NewExpression(
038                            NodeData xData, 
039                            Class<?> context, 
040                            Scan scan,
041                            RepositoryLanguage language, 
042                            Object environment) throws MesopotamiaException {
043                    super(xData, context, scan, language, environment);
044    
045                    Arguments = select(Expression.class, "ELIST/*");
046    //              TypeSpecification = (TypeSpecification) selectSingleElement(TypeSpecification.class, "TYPE");
047                    Fields = select(Field.class, "OBJBLOCK/*");
048                    
049                    LanguageElement firstChild = getChild(0);
050                    if (firstChild instanceof Type) {
051                            specType = (Type) firstChild;   
052    //                      if (language.supportsTokenName("TYPE_ARGUMENTS") && specType instanceof LanguageElement) {
053    //                              TypeArguments = ((LanguageElement) specType).select(TypeArgument.class, "TYPE_ARGUMENTS/TYPE_ARGUMENT");
054    //                      }                       
055                            MesopotamiaNode fNode = firstChild.getNode();
056                            List<MesopotamiaNode> siblings = fNode.getParent().getChildren();
057                            int nextSiblingPosition = fNode.getPosition()+1;
058                            if (siblings.size()>nextSiblingPosition) {
059                                    MesopotamiaNode nextSibling = siblings.get(nextSiblingPosition);
060                                    while ("ARRAY_DECLARATOR".equals(nextSibling.getTypeName())) {
061                                            ++dimensions;
062                                            siblings = nextSibling.getChildren();
063                                            if (siblings.isEmpty()) {
064                                                    break;
065                                            }
066                                            nextSibling = siblings.get(0);
067                                    }
068                            }
069                    }
070                    
071                    ArrayInitializers = select(ArrayInitializer.class, "ARRAY_INIT/*");
072            }
073    
074            public void toDom(Element holder) {
075                    super.toDom(holder);
076    
077                    // Serialize attributes
078    //              setElement(holder, "TypeArguments", TypeArguments);
079                    setElement(holder, "Arguments", Arguments);
080    //              setElement(holder, "TypeSpecification", TypeSpecification);
081            }
082    
083            // Attributes
084    //      private List<TypeArgument> TypeArguments = emptyList;
085    
086            private List<Expression> Arguments;
087    
088    //      private TypeSpecification TypeSpecification;
089    
090            private List<Field> Fields;
091            
092            // Accessors
093    //      public List<TypeArgument> getTypeArguments() {
094    //              return TypeArguments;
095    //      }
096    
097            public List<Expression> getArguments() {
098                    return Arguments;
099            }
100    
101    //      public TypeSpecification getTypeSpecification() {
102    //              return TypeSpecification;
103    //      }
104    
105            /**
106             * @return List of fields for anonymous classes
107             */
108            public List<Field> getFields() {
109                    return Fields;
110            }
111            
112            public Type getSpecificationType() {
113                    return specType;
114            }
115            
116            public int getDimensions() {
117                    return dimensions;
118            }
119            
120            public List<ArrayInitializer> getArrayInitializer() {
121                    return ArrayInitializers;
122            }
123    
124            protected void acceptChildren(Visitor visitor) {
125                    // Visiting non-text attributes
126    //              new CollectionVisitable(TypeArguments, false).accept(visitor);
127                    new CollectionVisitable(Arguments, false).accept(visitor);
128                    new CollectionVisitable(ArrayInitializers, false).accept(visitor);
129                    new CollectionVisitable(Fields, false).accept(visitor);
130            }
131    
132            public MethodInfo findMethod(String name, String[] parameterTypes) {
133                    MethodInfo candidate = findTypeMethod(name, parameterTypes);
134                    
135                    if (candidate!=null) {
136                            return candidate; // Does Java look for more specific methods in enclosed scope?
137                    }
138    
139                    Scope ec = findParent(Scope.class);
140                    return ec==null ? null : ec.findMethod(name, parameterTypes);
141            }
142    
143            public TypeInfo findType(String name) {
144                    TypeInfo ret = findNestedType(name);
145                    if (ret!=null) {
146                            return ret;
147                    }
148    
149                    Scope ec = findParent(Scope.class);
150                    return ec==null ? null : ec.findType(name);
151            }
152    
153            public VariableInfo findVariable(String name) {
154                    VariableInfo ret = findTypeVariable(name);
155                    if (ret!=null) {
156                            return ret;
157                    }
158    
159                    Scope ec = findParent(Scope.class);
160                    return ec==null ? null : ec.findVariable(name);
161            }
162    
163            public boolean isKindOf(String superFcn) {
164                    TypeSpecInfo tsi = getTypeSpecInfo();
165                    if (tsi!=null) {
166                            TypeInfo ti = TypeSpecification.toTypeInfo(tsi, findParent(Scope.class));
167                            if (ti!=null) {
168                                    return ti.isKindOf(superFcn);
169                            }
170                    }
171                    return JAVA_LANG_OBJECT.equals(superFcn);
172            }
173    
174            public String getFcn() {
175                    if (!fcnCalculated) {
176                            super.getFcn();
177                            SourceUnit su = getSourceUnit();
178                            if (su instanceof JavaSourceUnit) {
179                                    ((JavaSourceUnit) su).registerLocalOrAnonymous(fcn, this);
180                            }               
181                    }
182                    
183                    return fcn;                     
184            }
185    
186            public TypeInfo findNestedType(String name) {
187                    for (Field field: getFields()) {
188                            if (field instanceof TypeDefinition) {
189                                    final TypeDefinition td = (TypeDefinition) field;
190                                    if (td.getName().equals(name)) {
191                                            return td;
192                                    }
193                            }
194                    }
195                    
196                    TypeSpecInfo tsi = getTypeSpecInfo();
197                    if (tsi==null || tsi.getTypeInfo()==null) {
198                            return null;
199                    }
200                    TypeInfo ti = TypeSpecification.toTypeInfo(tsi, findParent(Scope.class));
201                    return ti==null ? null : ti.findNestedType(name); 
202            }
203    
204            public MethodInfo findTypeMethod(String name, String[] parameterTypes) {
205                    List<TypeSpecInfo> pTypes=new ArrayList<TypeSpecInfo>();
206                    boolean pTypesResolved = true;
207                    for (int i=0; parameterTypes!=null && i<parameterTypes.length; ++i) {
208                            if (parameterTypes[i]==null) {
209                                    StringBuffer sig = new StringBuffer();
210                                    for (String pt: parameterTypes) {
211                                            sig.append(sig.length()==0 ? "(" : ", ");
212                                            sig.append(pt);
213                                    }
214                                    sig.append(")");
215                                    logger.warning("Could not resolve method "+name+sig.toString()+" argument "+i+" type ["+getLocation()+"]");
216                                    pTypes.add(null);
217                                    pTypesResolved = false;
218                            } else {
219                                    int dimensions=0;
220                                    String typeName = parameterTypes[i];
221                                    while (typeName.endsWith(TypeSpecInfo.ARRAY_BRACKETS)) {
222                                            ++dimensions;
223                                            typeName=typeName.substring(0, typeName.length()-TypeSpecInfo.ARRAY_BRACKETS.length());
224                                    }
225                                    final TypeInfo ptInfo = findType(typeName);
226                                    if (ptInfo==null) {
227                                            logger.warning("Type "+ptInfo+" not found");
228                                            return null;
229                                    }
230                                    final int d = dimensions;
231                                    pTypes.add(new TypeSpecInfo() {
232            
233                                            public int getDimensions() {
234                                                    return d;
235                                            }
236            
237                                            public TypeInfo getTypeInfo() {
238                                                    return ptInfo;
239                                            }
240                                            
241                                    });
242                            }
243                    }
244            
245                    MethodInfo pnumMatch = null;
246                    MethodInfo candidate = null;
247                    for (Field field: getFields()) {
248                            if (field instanceof MethodDefinition) {
249                                    MethodDefinition method = (MethodDefinition) field;
250                                    if (!method.getName().equals(name)) {
251                                            continue;
252                                    }
253                                    
254                                    List<TypeSpecInfo> mTypes = method.getParameterTypes();                           
255                                    ParameterMatch matchResult = TypeDefinition.match(mTypes, pTypes);
256                                    if (matchResult == ParameterMatch.FULL_MATCH) {
257                                            return method;
258                                    } else if (matchResult == ParameterMatch.MATCH) {
259                                            candidate = TypeDefinition.selectMoreSpecific(candidate, method);
260                                    } else if (!pTypesResolved && pnumMatch==null) {
261                                            pnumMatch = method;
262                                    }
263                            }
264                    }
265                    
266                    TypeSpecInfo tsi = getTypeSpecInfo();
267                    if (tsi==null || tsi.getTypeInfo()==null) {
268                            return candidate==null ? pnumMatch : candidate;
269                    }
270                    TypeInfo ti = TypeSpecification.toTypeInfo(tsi, findParent(Scope.class));
271                    if (ti==null) {
272                            return candidate==null ? pnumMatch : candidate;                 
273                    }
274                    
275                    if (candidate==null && !pTypesResolved) {
276                            return pnumMatch;
277                    }
278                    
279                    return TypeDefinition.selectMoreSpecific(candidate, ti.findTypeMethod(name, parameterTypes)); 
280            }
281    
282            public VariableInfo findTypeVariable(String name) {
283                    for (Field field: getFields()) {
284                            if (field instanceof VariableDefinition) {
285                                    final VariableDefinition vd = (VariableDefinition) field;
286                                    if (vd.getName().equals(name)) {
287                                            return vd;
288                                    }
289                            }
290                    }
291    
292                    TypeSpecInfo tsi = getTypeSpecInfo();
293                    if (tsi==null || tsi.getTypeInfo()==null) {
294                            return null;
295                    }
296                    TypeInfo ti = TypeSpecification.toTypeInfo(tsi, findParent(Scope.class));
297                    return ti==null ? null : ti.findTypeVariable(name); 
298            }
299    
300    
301            public MethodInfo findConstructor(String[] argumentTypes) {
302                    // TODO ???
303                    return null;
304            }
305            
306            public TypeInfo getDeclaringType() {
307                    return null;
308            }
309    
310            public List<String> getModifiers() {
311                    return emptyList;
312            }
313    
314            public String getName() {
315                    return null;
316            }
317            
318            @Override
319            public TypeSpecInfo getTypeSpecInfo() {
320                    final Info info;
321                    if (specType instanceof Identifier) {
322                            Scope es = findParent(Scope.class);
323                            info = ((Identifier) specType).getInfo(es);
324                    } else {
325                             info = specType.getInfo();
326                    }
327                    
328                    return new TypeSpecInfo() {
329    
330                            public int getDimensions() {
331                                    return dimensions;
332                            }
333    
334                            public TypeInfo getTypeInfo() {
335                                    return info instanceof TypeInfo ? (TypeInfo) info : null;
336                            }
337                            
338                    };
339            }
340    
341            public MethodInfo getInfo() {                           
342                    Scope scope = findParent(Scope.class);
343                    if (scope == null) {
344                            return null;
345                    }
346                    
347                    List<Expression> args = getArguments();
348                    String[] argumentTypes = new String[args.size()];
349                    Iterator<Expression> it = args.iterator();
350                    for (int i=0; it.hasNext(); ++i) {
351                            argumentTypes[i] = TypeSpecification.toString(it.next().getTypeSpecInfo());
352                    }
353                    
354                    TypeInfo ti = TypeSpecification.toTypeInfo(getTypeSpecInfo(), scope);
355                    return ti==null ? null : ti.findConstructor(argumentTypes);             
356            }
357    }