Commits

Tim Vernum committed 441f396

Convert member references in all forms

Comments (0)

Files changed (18)

convert/source/java/main/org/adjective/syntactic/convert/j8to7/MemberReferenceConverter.java

 import org.adjective.syntactic.convert.j8to7.util.Importer;
 import org.adjective.syntactic.parser.ast.*;
 import org.adjective.syntactic.parser.node.ExpressionNode;
+import org.adjective.syntactic.parser.node.ExpressionSuffix;
 import org.adjective.syntactic.parser.node.StatementNode;
+import org.adjective.syntactic.parser.type.BaseType;
 import org.adjective.syntactic.parser.type.JavaType;
 import org.adjective.syntactic.parser.type.SimpleJavaType;
+import org.adjective.syntactic.parser.util.ModifierSet;
+
+import java.util.Arrays;
 
 public class MemberReferenceConverter extends AbstractASTConverter
 {
         final ASTFormalParameters parameters = makeFormalParameters(method);
         final ASTNameList exceptions = getExceptions(method);
 
-        StatementNode statement = null;
+        ExpressionNode expression = null;
         if (target instanceof ASTQualifiedIdentifier)
         {
             // Might be a class reference [static member ref, receiver member ref, or constructor ref]
             final TypeInfo refType = findType(target.as(ASTQualifiedIdentifier.class).getName());
             if (refType != null)
             {
-                statement = makeMethodBody(method, refType, reference);
+                expression = makeMethodBody(method, refType, reference);
             }
         }
-        if (statement == null)
+        if (expression == null)
         {
-            statement = makeMethodBody(method, target, reference);
+            expression = makeMethodBody(method, target, reference);
         }
 
+        final StatementNode statement;
+        if (method.getReturnType().getBaseType() == BaseType.VOID)
+        {
+            statement = new ASTExpressionStatement(expression);
+        }
+        else
+        {
+            statement = new ASTReturnStatement(expression);
+        }
         final ASTMethodBody body = new ASTMethodBody(new ASTBlock(statement));
         return new ASTMethodDeclaration(method.getReturnType(),
                                         new ASTIdentifier(method.getName()),
                                         body);
     }
 
-    private StatementNode makeMethodBody(final MethodInfo method, final ExpressionNode target, final ASTMemberReference reference)
+    private ExpressionNode makeMethodBody(final MethodInfo method, final ExpressionNode target, final ASTMemberReference reference)
     {
-        // TODO
-        return new ASTEmptyStatement();
+        final ASTArguments arguments = getArguments(method);
+        final String methodName = reference.getName().getIdentifier();
+        return makeMethodCall(target, methodName, arguments);
     }
 
-    private StatementNode makeMethodBody(final MethodInfo method, final TypeInfo refType, final ASTMemberReference reference)
+    private ExpressionNode makeMethodBody(final MethodInfo method, final TypeInfo refType, final ASTMemberReference reference)
     {
         final SimpleJavaType javaType = new SimpleJavaType(refType.getName());
+        final ASTArguments arguments = getArguments(method);
         if (reference.isConstructorReference())
         {
-            final String[] parameterNames = method.getParameterNames();
-            final ASTQualifiedIdentifier[] argNames = new ASTQualifiedIdentifier[parameterNames.length];
-            for (int i = 0; i < parameterNames.length; i++)
+            return new ASTAllocationExpression(javaType, arguments, null);
+        }
+        else
+        {
+            final String methodName = reference.getName().getIdentifier();
+            MethodInfo refMethod = refType.findMethod(methodName, arguments.getNumberOfArguments());
+            if (refMethod != null && refMethod.getModifiers().is(ModifierSet.Modifier.STATIC))
             {
-                argNames[i] = new ASTQualifiedIdentifier(parameterNames[i]);
+                return makeStaticMethodCall(javaType, refMethod, arguments);
             }
-            final ASTArguments arguments = new ASTArguments(new ASTArgumentList(argNames));
-            return new ASTReturnStatement(new ASTAllocationExpression(javaType, arguments, null));
+            if (arguments.getNumberOfArguments() > 0)
+            {
+                refMethod = refType.findMethod(methodName, arguments.getNumberOfArguments() - 1);
+                if (refMethod != null)
+                {
+                    return makeMethodCall(arguments.firstArgument(), refMethod, arguments.shift());
+                }
+            }
+            throw new ConversionException("Cannot find method " + methodName + " in " + refType);
         }
-        return new ASTEmptyStatement();
+    }
+
+    private ExpressionNode makeStaticMethodCall(final JavaType javaType, final MethodInfo refMethod, final ASTArguments arguments)
+    {
+        final ExpressionNode prefix = new ASTQualifiedIdentifier(javaType.getTypeName());
+        return makeMethodCall(prefix, refMethod, arguments);
+    }
+
+    private ExpressionNode makeMethodCall(final ExpressionNode prefix, final MethodInfo refMethod, final ASTArguments arguments)
+    {
+        final String methodName = refMethod.getName();
+        return makeMethodCall(prefix, methodName, arguments);
+    }
+
+    private ExpressionNode makeMethodCall(final ExpressionNode prefix, final String methodName, final ASTArguments arguments)
+    {
+        final ASTIdentifierSuffix member = new ASTIdentifierSuffix(new ASTIdentifier(methodName));
+        return new ASTPrimaryExpression(prefix,
+                                        Arrays.<ExpressionSuffix>asList(new ASTMemberSuffix(member), arguments));
+    }
+
+    private ASTArguments getArguments(final MethodInfo method)
+    {
+        final String[] parameterNames = method.getParameterNames();
+        final ASTQualifiedIdentifier[] argNames = new ASTQualifiedIdentifier[parameterNames.length];
+        for (int i = 0; i < parameterNames.length; i++)
+        {
+            argNames[i] = new ASTQualifiedIdentifier(parameterNames[i]);
+        }
+        return new ASTArguments(new ASTArgumentList(argNames));
     }
 
     private ASTFormalParameters makeFormalParameters(final MethodInfo method)
                                                          parameterNames[i]);
         }
         return new ASTFormalParameters(formalParameters);
-
     }
 }

convert/source/java/main/org/adjective/syntactic/convert/j8to7/type/AbstractMethodInfo.java

         }
         return true;
     }
+
+    @Override
+    public int getParameterCount()
+    {
+        return getParameterTypes().length;
+    }
 }

convert/source/java/main/org/adjective/syntactic/convert/j8to7/type/AbstractTypeInfo.java

         }
         return filter;
     }
+
+    @Override
+    public MethodInfo findMethod(final String identifier, final int parameterCount)
+    {
+        for (MethodInfo method : getMethods())
+        {
+            if (identifier.equals(method.getName()) && method.getParameterCount() == parameterCount)
+            {
+                return method;
+            }
+        }
+        return null;
+    }
 }

convert/source/java/main/org/adjective/syntactic/convert/j8to7/type/ClassInfo.java

         return null;
     }
 
+    @Override
+    public String toString()
+    {
+        if (_parameters.length == 0)
+        {
+            return _cls.getName();
+        }
+        StringBuilder builder = new StringBuilder(_cls.getName());
+        builder.append("<");
+        for (TypeParameter parameter : _parameters)
+        {
+            builder.append(parameter).append(",");
+        }
+        builder.setCharAt(builder.length() - 1, '>');
+        return builder.toString();
+    }
 }

convert/source/java/main/org/adjective/syntactic/convert/j8to7/type/MethodInfo.java

     public String getName();
     public ModifierSet getModifiers();
     public JavaType getReturnType();
+    public int getParameterCount();
     public JavaType[] getParameterTypes();
     public String[] getParameterNames();
 

convert/source/java/main/org/adjective/syntactic/convert/j8to7/type/TypeInfo.java

     public String getName();
     public MethodInfo[] getMethods();
     public Collection<MethodInfo> getAbstractMethods();
+    public MethodInfo findMethod(final String name, final int parameterCount);
 }

parser/source/grammar/java.jjt

         Super()
       | This()
       | AllocationExpression() 
-      | [ TypeArguments() ] Identifier()
+      | IdentifierSuffix()
       ) #MemberSuffix
 |
   ArrayIndex()
   MethodOrConstructorReference()
 }
 
+void IdentifierSuffix() :
+{}
+{
+    [ TypeArguments() ] Identifier()
+}
+
 void MethodOrConstructorReference() #MemberReference : 
 {}
 {

parser/source/java/parser/org/adjective/syntactic/parser/ast/ASTArguments.java

 import org.adjective.syntactic.parser.node.BaseNode;
 import org.adjective.syntactic.parser.node.ExpressionSuffix;
 
+import java.util.Iterator;
+
 public class ASTArguments extends BaseNode implements ExpressionSuffix
 {
     public ASTArguments(int id)
         setChildren(argumentList);
     }
 
-    public <R,T> R jjtAccept(JavaParserVisitor<R,T> visitor, T data)
+    public <R, T> R jjtAccept(JavaParserVisitor<R, T> visitor, T data)
     {
         return visitor.visit(this, data);
     }
     {
         return optionalChild(ASTArgumentList.class);
     }
+
+    public ASTExpression firstArgument()
+    {
+        return getArguments().getArguments().first();
+    }
+
+    public ASTArguments shift()
+    {
+        final ASTArgumentList arguments = getArguments();
+        final Iterator<ASTExpression> iterator = arguments.getArguments().iterator();
+        iterator.next();
+
+        final ASTExpression[] expressions = new ASTExpression[arguments.jjtGetNumChildren() - 1];
+        for (int i = 0; i < expressions.length; i++)
+        {
+            expressions[i] = iterator.next();
+        }
+
+        return new ASTArguments(new ASTArgumentList(expressions));
+    }
+
+    public int getNumberOfArguments()
+    {
+        final ASTArgumentList arguments = getArguments();
+        if (arguments == null)
+        {
+            return 0;
+        }
+        return arguments.jjtGetNumChildren();
+    }
 }

parser/source/java/parser/org/adjective/syntactic/parser/ast/ASTBooleanLiteral.java

 package org.adjective.syntactic.parser.ast;
 
+import org.adjective.syntactic.parser.jj.JavaParserConstants;
 import org.adjective.syntactic.parser.node.BaseNode;
-import org.adjective.syntactic.parser.jj.JavaParserConstants;
 import org.adjective.syntactic.parser.node.ExpressionNode;
 
 public class ASTBooleanLiteral extends BaseNode implements ExpressionNode
         super(id);
     }
 
+    public ASTBooleanLiteral(boolean value)
+    {
+        this(JavaParserTreeConstants.JJTBOOLEANLITERAL);
+        if (value)
+        {
+            jjtSetFirstToken(makeToken(JavaParserConstants.TRUE,
+                                       "true"));
+        }
+        else
+        {
+            jjtSetFirstToken(makeToken(JavaParserConstants.FALSE,
+                                       "false"));
+        }
+    }
+
     public <R, T> R jjtAccept(JavaParserVisitor<R, T> visitor, T data)
     {
         return visitor.visit(this, data);

parser/source/java/parser/org/adjective/syntactic/parser/ast/ASTExpressionStatement.java

         super(i);
     }
 
+    public ASTExpressionStatement(final ExpressionNode expression)
+    {
+        this(JavaParserTreeConstants.JJTEXPRESSIONSTATEMENT);
+        setChildren(expression);
+    }
+
     @Override
     public <R,T> R jjtAccept(final JavaParserVisitor<R,T> visitor, final T data)
     {

parser/source/java/parser/org/adjective/syntactic/parser/ast/ASTIdentifierSuffix.java

+/* ------------------------------------------------------------------------
+ * Copyright 2013 Tim Vernum
+ * ------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ------------------------------------------------------------------------
+ */
+package org.adjective.syntactic.parser.ast;
+
+import org.adjective.syntactic.parser.node.BaseNode;
+import org.adjective.syntactic.parser.node.MemberExpressionNode;
+
+public class ASTIdentifierSuffix extends BaseNode implements MemberExpressionNode
+{
+    public ASTIdentifierSuffix(final int i)
+    {
+        super(i);
+    }
+
+    public ASTIdentifierSuffix(ASTTypeArguments typeArguments, ASTIdentifier identifier)
+    {
+        this(JavaParserTreeConstants.JJTIDENTIFIERSUFFIX);
+        setChildren(typeArguments, identifier);
+    }
+
+    public ASTIdentifierSuffix(ASTIdentifier identifier)
+    {
+        this(JavaParserTreeConstants.JJTIDENTIFIERSUFFIX);
+        setChildren(identifier);
+    }
+
+    @Override
+    public <R, T> R jjtAccept(final JavaParserVisitor<R, T> visitor, final T data)
+    {
+        return visitor.visit(this, data);
+    }
+
+    public ASTIdentifier getIdentifier()
+    {
+        return getLastChild().as(ASTIdentifier.class);
+    }
+}

parser/source/java/parser/org/adjective/syntactic/parser/ast/ASTMemberSuffix.java

         return visitor.visit(this, data);
     }
 
+    public MemberExpressionNode getExpression()
+    {
+        return getFirstChild().as(MemberExpressionNode.class);
+    }
 }

parser/source/java/parser/org/adjective/syntactic/parser/ast/ASTTypeArgument.java

 package org.adjective.syntactic.parser.ast;
 
+import org.adjective.syntactic.parser.name.TypeParameter;
 import org.adjective.syntactic.parser.node.BaseNode;
+import org.adjective.syntactic.parser.node.TypeNode;
 import org.adjective.syntactic.parser.type.JavaType;
-import org.adjective.syntactic.parser.node.TypeNode;
-import org.adjective.syntactic.parser.name.TypeParameter;
 import org.adjective.syntactic.parser.type.SimpleJavaType;
 
 public class ASTTypeArgument extends BaseNode implements TypeParameter
         {
             return Kind.EXTENDS;
         }
-        if(isWildcard()) {
+        if (isWildcard())
+        {
             return getFirstChild().as(ASTWildcardBounds.class).getKind();
-        } else {
+        }
+        else
+        {
             return Kind.EXACT;
         }
     }
         {
             return new SimpleJavaType("Object");
         }
-        if(isWildcard()) {
+        if (isWildcard())
+        {
             return getFirstChild().as(ASTWildcardBounds.class).getType();
-        } else {
+        }
+        else
+        {
             return getFirstChild().as(TypeNode.class);
         }
     }

parser/source/java/parser/org/adjective/syntactic/parser/ast/SimpleNode.java

 
     public void jjtAddChild(Node n, int i)
     {
+        if (n == null)
+        {
+            throw new IllegalArgumentException("Cannot add null child");
+        }
         if (children == null)
         {
             children = new Node[i + 1];

parser/source/java/parser/org/adjective/syntactic/parser/node/AbstractNodeList.java

         }
         return null;
     }
+
+    @Override
+    public T first()
+    {
+        return iterator().next();
+    }
 }

parser/source/java/parser/org/adjective/syntactic/parser/node/Nodes.java

     public int size();
     public boolean has(Class<? extends Node> type);
     public <N extends Node> N find(Class<? extends N> type);
+    public T first();
 }

parser/source/java/parser/org/adjective/syntactic/parser/util/DefaultVisitor.java

     }
 
     @Override
+    public R visit(final ASTIdentifierSuffix node, final T data)
+    {
+        node.childrenAccept(this, data);
+        return null;
+    }
+
+    @Override
     public R visit(final ASTMemberReference node, final T data)
     {
         node.childrenAccept(this, data);

parser/source/java/parser/org/adjective/syntactic/parser/util/PrintSourceVisitor.java

     }
 
     @Override
+    public Object visit(final ASTIdentifierSuffix node, final PrintStream out)
+    {
+        node.childrenAccept(this, out);
+        return null;
+    }
+
+    @Override
     public Object visit(final ASTMemberReference node, final PrintStream out)
     {
         out.print("::");