| /*=============================================================================# |
| # Copyright (c) 2007, 2020 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.r.core.rsource.ast; |
| |
| import static org.eclipse.statet.r.core.rsource.IRSourceConstants.STATUS_OK; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.List; |
| |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.ltk.ast.core.AstNode; |
| import org.eclipse.statet.ltk.ast.core.impl.AbstractAstNode; |
| import org.eclipse.statet.r.core.rlang.RTerminal; |
| |
| |
| /** |
| * A node of a R AST |
| */ |
| @NonNullByDefault |
| public abstract class RAstNode extends AbstractAstNode |
| implements AstNode { |
| |
| |
| interface Assoc { |
| byte TERM= 1; |
| byte CONTAINER= 2; |
| byte NOSTD= 3; |
| byte LEFTSTD= 4; |
| byte RIGHTSTD= 5; |
| } |
| |
| |
| static final RAstNode[] NO_CHILDREN= new RAstNode[0]; |
| |
| |
| @Nullable RAstNode rParent; |
| int startOffset; |
| int endOffset; |
| int status; |
| |
| |
| protected RAstNode() { |
| this.status= STATUS_OK; |
| } |
| |
| protected RAstNode(final int status) { |
| this.status= status; |
| } |
| |
| |
| public abstract NodeType getNodeType(); |
| |
| public abstract @Nullable RTerminal getOperator(final int index); |
| |
| @Override |
| public final int getStatusCode() { |
| return this.status; |
| } |
| |
| |
| /** |
| * @return the parent node, if it is an RAstNode too, otherwise <code>null</code> |
| */ |
| public @Nullable RAstNode getRParent() { |
| return this.rParent; |
| } |
| |
| @Override |
| public @Nullable AstNode getParent() { |
| return this.rParent; |
| } |
| |
| public final RAstNode getRRoot() { |
| RAstNode candidate= this; |
| RAstNode p; |
| while ((p= candidate.rParent) != null) { |
| candidate= p; |
| } |
| return candidate; |
| } |
| |
| @Override |
| public abstract boolean hasChildren(); |
| @Override |
| public abstract int getChildCount(); |
| @Override |
| public abstract RAstNode getChild(int index); |
| public abstract RAstNode[] getChildren(); |
| @Override |
| public abstract int getChildIndex(AstNode child); |
| |
| |
| @Override |
| public int getStartOffset() { |
| return this.startOffset; |
| } |
| |
| @Override |
| public final int getEndOffset() { |
| return this.endOffset; |
| } |
| |
| @Override |
| public final int getLength() { |
| return this.endOffset - this.startOffset; |
| } |
| |
| |
| int getEqualsIndex(final RAstNode element) { |
| final RAstNode[] children= getChildren(); |
| int index= 0; |
| for (final RAstNode child : children) { |
| if (child == element) { |
| return index; |
| } |
| if (child.equalsSingle(element)) { |
| index++; |
| } |
| } |
| return -1; |
| } |
| |
| |
| public abstract void acceptInR(RAstVisitor visitor) throws InvocationTargetException; |
| |
| public abstract void acceptInRChildren(RAstVisitor visitor) throws InvocationTargetException; |
| |
| protected final void acceptChildren(final RAstVisitor visitor, final List<? extends RAstNode> children) throws InvocationTargetException { |
| for (final RAstNode child : children) { |
| child.acceptInR(visitor); |
| } |
| } |
| |
| protected final void acceptChildrenExpr(final RAstVisitor visitor, final List<Expression> children) throws InvocationTargetException { |
| for (final Expression expr : children) { |
| expr.node.acceptInR(visitor); |
| } |
| } |
| |
| |
| abstract @Nullable Expression getExpr(RAstNode child); |
| abstract @Nullable Expression getLeftExpr(); |
| abstract @Nullable Expression getRightExpr(); |
| |
| public final boolean equalsIgnoreAst(final Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (!(obj instanceof RAstNode) || !equalsSingle((RAstNode) obj)) { |
| return false; |
| } |
| |
| RAstNode me= this; |
| RAstNode other= (RAstNode) obj; |
| while (me != other) { |
| if (me.rParent == null || other.rParent == null) { |
| return (me.rParent == null && other.rParent == null); |
| } |
| if ((!me.rParent.equalsSingle(other.rParent)) |
| || (me.rParent.getEqualsIndex(me) != other.rParent.getEqualsIndex(other)) |
| ) { |
| return false; |
| } |
| me= me.rParent; |
| other= other.rParent; |
| } |
| return true; |
| } |
| |
| abstract boolean equalsSingle(RAstNode element); |
| |
| public boolean equalsValue(final RAstNode element) { |
| if (getNodeType() != element.getNodeType()) { |
| return false; |
| } |
| final int count= getChildCount(); |
| if (count != element.getChildCount()) { |
| return false; |
| } |
| for (int i= 0; i < count; i++) { |
| if (!getChild(i).equalsValue(element.getChild(i))) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| void appendPathElement(final StringBuilder s) { |
| // if (parent != null) { |
| // s.append(parent.getEqualsIndex(this)); |
| // } |
| s.append('$'); |
| s.append(getNodeType().ordinal()); |
| } |
| |
| public int hashCodeIgnoreAst() { |
| final StringBuilder path= new StringBuilder(); |
| if (this.rParent != null) { |
| if (this.rParent.rParent != null) { |
| path.append(this.rParent.rParent.getNodeType().ordinal()); |
| } |
| path.append('$'); |
| path.append(this.rParent.getNodeType().ordinal()); |
| } |
| appendPathElement(path); |
| return path.toString().hashCode(); |
| } |
| |
| @Override |
| public String toString() { |
| final StringBuilder s= new StringBuilder(); |
| // s.append("«"); |
| s.append(getNodeType().label); |
| // s.append(" § " + startOffset + "," + endOffset); |
| // s.append("»"); |
| return s.toString(); |
| } |
| |
| |
| abstract int getMissingExprStatus(Expression expr); |
| |
| abstract void updateEndOffset(); |
| |
| |
| } |