package org.elixir_lang.psi.operation.infix;
import com.intellij.psi.PsiElement;
import org.elixir_lang.psi.Operator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import static com.intellij.psi.util.PsiTreeUtil.isAncestor;
import static org.elixir_lang.psi.operation.Normalized.operatorIndex;
/**
* Partitions children into those left of the operator, the operator, and those right of the operator. This will
* include any error elements and the left or right children may be empty if there are other parsing errors with
* recovery.
*/
public class Triple {
/*
* Fields
*/
@NotNull
public final PsiElement[] leftOperands;
@NotNull
public final PsiElement operator;
@NotNull
public final PsiElement[] rightOperands;
/*
* Constructors
*/
public Triple(@NotNull PsiElement[] children) {
this(children, operatorIndex(children));
}
private Triple(@NotNull PsiElement[] children, int operatorIndex) {
this(
Arrays.copyOfRange(children, 0, operatorIndex),
(Operator) children[operatorIndex],
Arrays.copyOfRange(children, operatorIndex + 1, children.length)
);
}
private Triple(@NotNull PsiElement[] leftOperands, @NotNull Operator operator, @NotNull PsiElement[] rightOperands) {
this.leftOperands = leftOperands;
this.operator = operator;
this.rightOperands = rightOperands;
}
/*
*
* Instance Methods
*
*/
/**
*
* @param element an element that MAY be an descendant of a child of this triple
* @return {@code null} if element is not a descendant of any children in this Triple.
*/
@Nullable
public Position ancestorPosition(@NotNull PsiElement element) {
Position position = null;
if (isAnyAncestor(leftOperands, element)) {
position = Position.LEFT;
} else if (isAnyAncestor(rightOperands, element)) {
position = Position.RIGHT;
} else if (isAncestor(operator, element, false)) {
position = Position.OPERATOR;
}
return position;
}
/*
* Private Instance Methods
*/
private boolean isAnyAncestor(@NotNull PsiElement[] operands, @NotNull PsiElement element) {
boolean isAnyAncestor = false;
for (PsiElement operand : operands) {
if (isAncestor(operand, element, false)) {
isAnyAncestor = true;
break;
}
}
return isAnyAncestor;
}
}