All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.codegen.MethodTemplate Maven / Gradle / Ivy

/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.codegen;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Objects.requireNonNull;
import static org.neo4j.codegen.Parameter.NO_PARAMETERS;
import static org.neo4j.codegen.TypeReference.NO_TYPES;
import static org.neo4j.codegen.TypeReference.typeReference;

public class MethodTemplate
{
    public static Builder method( Class returnType, String name, Parameter... parameters )
    {
        return method( typeReference( returnType ), name, parameters );
    }

    public static Builder method( final TypeReference returnType, final String name, Parameter... parameters )
    {
        try
        {
            return new Builder( parameters )
            {
                @Override
                public MethodTemplate build()
                {
                    return buildMethod( this, returnType, name );
                }

                @Override
                MethodDeclaration.Builder declaration()
                {
                    return MethodDeclaration.method( returnType, name, parameters );
                }
            };
        }
        catch ( IllegalArgumentException | NullPointerException e )
        {
            throw new IllegalArgumentException( "Invalid signature for " + name + ": " + e.getMessage(), e );
        }
    }

    public static ConstructorBuilder constructor( Parameter... parameters )
    {
        try
        {
            return new ConstructorBuilder( parameters );
        }
        catch ( IllegalArgumentException | NullPointerException e )
        {
            throw new IllegalArgumentException( "Invalid constructor signature: " + e.getMessage(), e );
        }
    }

    public static class ConstructorBuilder extends Builder
    {
        ConstructorBuilder( Parameter[] parameters )
        {
            super( parameters );
        }

        public Builder invokeSuper()
        {
            return expression(
                    ExpressionTemplate.invokeSuperConstructor( new ExpressionTemplate[]{}, TypeReference.NO_TYPES ) );
        }

        public Builder invokeSuper( ExpressionTemplate[] parameters, Class[] parameterTypes )
        {
            TypeReference[] references = new TypeReference[parameterTypes.length];
            for ( int i = 0; i < parameterTypes.length; i++ )
            {
                references[i] = typeReference( parameterTypes[i] );
            }

            return invokeSuper( parameters, references );
        }

        public Builder invokeSuper( ExpressionTemplate[] parameters, TypeReference[] parameterTypes )
        {
            return expression( ExpressionTemplate.invokeSuperConstructor( parameters, parameterTypes ) );
        }

        @Override
        public MethodTemplate build()
        {
            return buildConstructor( this );
        }

        @Override
        MethodDeclaration.Builder declaration()
        {
            return MethodDeclaration.constructor( parameters );
        }
    }

    public abstract static class Builder
    {
        final Parameter[] parameters;
        private final Map locals = new HashMap<>();
        private final List statements = new ArrayList<>();
        private int modifiers = Modifier.PUBLIC;

        Builder( Parameter[] parameters )
        {
            if ( parameters == null || parameters.length == 0 )
            {
                this.parameters = NO_PARAMETERS;
            }
            else
            {
                this.parameters = parameters.clone();
            }
            for ( int i = 0; i < this.parameters.length; i++ )
            {
                Parameter parameter = requireNonNull( this.parameters[i], "Parameter " + i );
                if ( null != locals.put( parameter.name(), parameter.type() ) )
                {
                    throw new IllegalArgumentException( "Duplicate parameters named \"" + parameter.name() + "\"." );
                }
            }
        }

        public abstract MethodTemplate build();

        public Builder expression( ExpressionTemplate expression )
        {
            statements.add( Statement.expression( expression ) );
            return this;
        }

        public Builder put( ExpressionTemplate target, Class fieldType, String fieldName,
                ExpressionTemplate expression )
        {
            return put( target, typeReference( fieldType ), fieldName, expression );
        }

        public Builder put( ExpressionTemplate target, TypeReference fieldType, String fieldName,
                ExpressionTemplate expression )
        {
            statements.add( Statement.put( target, Lookup.field( fieldType, fieldName ), expression ) );
            return this;
        }

        public Builder modifiers( int modifiers )
        {
            this.modifiers = modifiers;
            return this;
        }

        public Builder returns( ExpressionTemplate value )
        {
            statements.add( Statement.returns( value ) );
            return this;
        }

        abstract MethodDeclaration.Builder declaration();
    }

    public TypeReference returnType()
    {
        return returnType;
    }

    public String name()
    {
        return name;
    }

    public int modifiers()
    {
        return modifiers;
    }

    public TypeReference[] parameterTypes()
    {
        if ( parameters.length == 0 )
        {
            return NO_TYPES;
        }
        TypeReference[] result = new TypeReference[parameters.length];
        for ( int i = 0; i < result.length; i++ )
        {
            result[i] = parameters[i].type();
        }
        return result;
    }

    MethodDeclaration declaration( ClassHandle handle )
    {
        return declaration.build( handle );
    }

    void generate( CodeBlock generator )
    {
        for ( Statement statement : statements )
        {
            statement.generate( generator );
        }
    }

    private static MethodTemplate buildMethod( Builder builder, TypeReference returnType, String name )
    {
        return new MethodTemplate( builder, returnType, name );
    }

    private static MethodTemplate buildConstructor( Builder builder )
    {
        return new MethodTemplate( builder, TypeReference.VOID, "" );
    }

    private final MethodDeclaration.Builder declaration;
    private final Parameter[] parameters;
    private final Statement[] statements;
    private final TypeReference returnType;
    private final String name;
    private final int modifiers;

    private MethodTemplate( Builder builder, TypeReference returnType, String name )
    {
        this.returnType = returnType;
        this.name = name;
        this.declaration = builder.declaration();
        this.parameters = builder.parameters;
        this.statements = builder.statements.toArray( new Statement[builder.statements.size()] );
        this.modifiers = builder.modifiers;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy