org.lambdamatic.analyzer.ast.node.ArrayVariable.java Source code

Java tutorial

Introduction

Here is the source code for org.lambdamatic.analyzer.ast.node.ArrayVariable.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Red Hat. All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v1.0 which accompanies this
 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors: Red Hat - Initial Contribution
 *******************************************************************************/

package org.lambdamatic.analyzer.ast.node;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.ArrayUtils;

/**
 * Array created and used during the call to the Lambda Expression serialized method.
 * 
 * @author Xavier Coulon
 *
 */
public class ArrayVariable extends ComplexExpression {

    /** the expression on which the method call is applied. */
    private final Class<?> instanceType;

    /** the underlying array elements. */
    private final Expression[] elements;

    /**
     * Initializes an {@link ArrayVariable} from the given elements.
     * 
     * @param instanceType the type of elements in the array
     * @param elements the actual elements in the array
     * @param <T> the instance type
     */
    public <T> ArrayVariable(final Class<T> instanceType, final Expression... elements) {
        this(instanceType, elements.length);
        System.arraycopy(elements, 0, this.elements, 0, elements.length);
        Stream.of(this.elements).forEach(e -> e.setParent(this));
    }

    /**
     * Full constructor.
     * <p>
     * Note: the synthetic {@code id} is generated and the inversion flag is set to {@code false}.
     * </p>
     * 
     * @param instanceType the type of the instance to build
     * @param length the length of the underlying array
     */
    public ArrayVariable(final Class<?> instanceType, final int length) {
        this(generateId(), instanceType, length, false);
    }

    /**
     * Full constructor.
     * <p>
     * Note: the synthetic {@code id} is generated and the inversion flag is set to {@code false}.
     * </p>
     * 
     * @param instanceType the type of the instance to build
     * @param length the length of the underlying array
     * @param inverted the inversion flag
     */
    public ArrayVariable(final Class<?> instanceType, final int length, boolean inverted) {
        this(generateId(), instanceType, length, inverted);
    }

    /**
     * Full constructor.
     * <p>
     * Note: the synthetic {@code id} is generated and the inversion flag is set to {@code false}.
     * </p>
     * 
     * @param id the id of this expression
     * @param instanceType the type of the instance to build
     * @param length the length of the underlying array
     * @param inverted the inversion flag
     */
    public ArrayVariable(final int id, final Class<?> instanceType, final int length, boolean inverted) {
        super(id, inverted);
        this.instanceType = instanceType;
        this.elements = new Expression[length];
    }

    /**
     * @see org.lambdamatic.analyzer.ast.node.Expression#getExpressionType()
     */
    @Override
    public ExpressionType getExpressionType() {
        return ExpressionType.ARRAY_VARIABLE;
    }

    /**
     * @see org.lambdamatic.analyzer.ast.node.Expression#getJavaType()
     */
    @Override
    public Class<?> getJavaType() {
        return this.instanceType;
    }

    /**
     * @return the {@link Expression} element of this {@link ArrayVariable}.
     */
    @Override
    public Object getValue() {
        final Class<?> arrayType = this.instanceType.isArray() ? this.instanceType.getComponentType()
                : this.instanceType;
        final Object[] values = (Object[]) Array.newInstance(arrayType, new int[] { this.elements.length });
        for (int i = 0; i < this.elements.length; i++) {
            values[i] = this.elements[i].getValue();
        }
        return values;
    }

    /**
     * @return the elements contained in this array.
     */
    public Expression[] getElements() {
        return this.elements;
    }

    @Override
    public boolean anyElementMatches(ExpressionType type) {
        return Stream.of(this.elements).anyMatch(e -> e.anyElementMatches(type));
    }

    /**
     * Sets the given {@code element} at the given {@code index} in the underlying array of
     * {@link Expression}.
     * 
     * @param index the index in the array
     * @param element the element to add
     */
    public void setElement(final int index, final Expression element) {
        this.elements[index] = element;
        element.setParent(this);
    }

    /**
     * @see org.lambdamatic.analyzer.ast.node.Expression#canBeInverted()
     */
    @Override
    public boolean canBeInverted() {
        return false;
    }

    /**
     * @see org.lambdamatic.analyzer.ast.node.Expression#duplicate(int)
     */
    @Override
    public Expression duplicate(int id) {
        final ArrayVariable arrayVariable = new ArrayVariable(id, this.instanceType, this.elements.length,
                isInverted());
        for (int i = 0; i < this.elements.length; i++) {
            arrayVariable.setElement(i, this.elements[i].duplicate());
        }
        return arrayVariable;
    }

    @Override
    public void accept(final ExpressionVisitor visitor) {
        if (visitor.visit(this)) {
            for (Expression element : this.elements) {
                element.accept(visitor);
            }
        }
    }

    @Override
    public void replaceElement(final Expression oldElementExpression, final Expression newElementExpression) {
        final int oldExpressionIndex = ArrayUtils.indexOf(this.elements, oldElementExpression);
        if (oldExpressionIndex > -1) {
            this.elements[oldExpressionIndex] = newElementExpression;
            newElementExpression.setParent(this);
        }
    }

    @Override
    public String toString() {
        return this.instanceType.getName()
                + Stream.of(this.elements).map(Expression::toString).collect(Collectors.toList());
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + Arrays.hashCode(this.elements);
        result = prime * result + ((this.instanceType == null) ? 0 : this.instanceType.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ArrayVariable other = (ArrayVariable) obj;
        if (!Arrays.equals(this.elements, other.elements)) {
            return false;
        }
        if (this.instanceType == null) {
            if (other.instanceType != null) {
                return false;
            }
        } else if (!this.instanceType.equals(other.instanceType)) {
            return false;
        }
        return true;
    }

}