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

io.deephaven.lang.generated.Node Maven / Gradle / Ivy

There is a newer version: 0.36.1
Show newest version
/* Generated By:JJTree: Do not edit this line. Node.java Version 7.0 */
/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=Chunker,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
package io.deephaven.lang.generated;

/* All AST nodes must implement this interface.  It provides basic
   machinery for constructing the parent and child relationships
   between nodes. */

import io.deephaven.lang.api.IsScope;
import io.deephaven.lang.parse.LspTools;
import io.deephaven.proto.backplane.script.grpc.DocumentRange;
import io.deephaven.proto.backplane.script.grpc.Position;
import io.deephaven.proto.backplane.script.grpc.PositionOrBuilder;
import io.deephaven.web.shared.fu.LinkedIterable;

import java.util.List;

import static java.util.Collections.singletonList;

public interface Node {

    /** This method is called after the node has been made the current
     node.  It indicates that child nodes can now be added to it. */
    void jjtOpen();

    /** This method is called after all the child nodes have been
     added. */
    void jjtClose();

    /** This pair of methods are used to inform the node of its
     parent. */
    void jjtSetParent(Node n);
    Node jjtGetParent();

    /** This method tells the node to add its argument to the node's
     list of children.  */
    void jjtAddChild(Node n, int i);

    /** This method inserts the specified node at the given index, shifting any existing items to the right.  */
    void jjtInsertChild(Node n, int i);

    /** This method returns a child node.  The children are numbered
     from zero, left to right. */
    Node jjtGetChild(int i);

    /** Return the number of children the node has. */
    int jjtGetNumChildren();

    int getId();

    Token jjtGetFirstToken();

    void jjtSetFirstToken(Token token);

    Token jjtGetLastToken();

    void jjtSetLastToken(Token token);

    default LinkedIterable tokens(boolean strict) {
        return new LinkedIterable<>(jjtGetFirstToken(), jjtGetLastToken(), true, strict, Token::next);
    }

    default LinkedIterable tokensReversed(boolean strict) {
        return new LinkedIterable<>(jjtGetLastToken(), jjtGetFirstToken(), true, strict, Token::prev);
    }

    default void addToken(Token token) {
        addToken(token, null);
    }
    void addToken(Token token, Node anchor);

    default Node rescope(List scope) {
        if (scope != null) {
            addScope(scope);
        }
        return this;
    }

    default void setScope(List scope) {
        throw new UnsupportedOperationException(getClass() + " does not support scope!");
    }

    /** Accept the visitor. **/
    Object jjtAccept(ChunkerVisitor visitor, Object data);

    void adopt(Node node);

    default boolean containsIndex(int i) {
        return getStartIndex() <= i &&
               getEndIndex() > i;
    }

    default boolean isChildOf(Node best) {
        for (Node parent : new LinkedIterable<>(Node.this, Node::jjtGetParent)) {
            if (parent == best) {
                return true;
            }
        }
        return false;
    }

    Token addJunk(Token junk);

    default String toSource() {
        // Return exactly to the original source;
        // we turn all tokens into nodes, including whitespace,
        // so this should be a 1:1 mapping of original source.
        // When we perform autocompletion, we may want to adjust some values,
        // like "strings " + " that are appended" into a single entity, w/ adjusted cursor,
        // ...though that likely won't happen until we run out of more useful things to do.
        StringBuilder b = new StringBuilder();
        Token next = jjtGetFirstToken();
        while (next != jjtGetLastToken()) {
            append(b, next);
            if (next == next.next) {
                break;
            }
            next = next.next;
        }
        append(b, next);
        return b.toString();
    }

    default /*private*/ void append(StringBuilder b, Token tok) {
        if (tok.specialToken != null) {
            append(b, tok.specialToken);
        }
        b.append(tok.image);
    }

    default int getEndIndex() {
        final Token lastToken = jjtGetLastToken();
        if (lastToken.kind == ChunkerConstants.EOF) {
            // document ended with a comment; use said comment as the end index.
            return lastToken.getEndIndex() + lastToken.specialTokenLength();
        }
        return lastToken.getEndIndex();
    }

    default int getStartIndex() {
        Token firstToken = jjtGetFirstToken();
        int ind = firstToken.getStartIndex();
        return ind;
    }

    List getChildren();

    /**
     * Overridden manually for nodes who can "have a cursor on them" with respect to autocomplete.
     *
     * If any part of an ast node collects tokens that are "leaf nodes" (i.e. there are cursor positions
     * where your ast node will be the most derived child found), then it is a candidate to be a terminal autocomplete source.
     *
     * When encountering whitespace or . or , we might search left or right for interesting nodes,
     * and those ast nodes who are autocomplete terminal will be preferred over their children.
     *
     * The normal search algorithm is a standard binary tree search, where the next-leftmost|rightmost leaf node is transversed.
     * When an `isAutocompleteTerminal() == true` node is found, however, we stop there to continue searches.
     *
     * @return true for nodes that the visitor in ChunkerCompleter will visit and generate results.
     *
     * This is not needed for always-terminal nodes, like ChunkerNum or ChunkerIdent, but is needed by terminal-nodes-with-children,
     * like ChunkerInvoke or ChunkerNew.
     *
     */
    default boolean isAutocompleteTerminal() {
        return false;
    }

    boolean isWellFormed();

    default void addChild(Node child) {
        if (jjtGetFirstToken() == null) {
            jjtSetFirstToken(child.jjtGetFirstToken());
        }
        addChild(child, jjtGetNumChildren());
    }

    default void addChild(Node child, int index) {
        child.maybeDetach();
        child.jjtSetParent(this);
        jjtAddChild(child, index);
    }
    default void insertChild(Node child, int index) {
        child.maybeDetach();
        child.jjtSetParent(this);
        jjtInsertChild(child, index);
        if (index == 0) {
            jjtSetFirstToken(child.jjtGetFirstToken());
        } else if (index == jjtGetNumChildren()) {
            jjtSetLastToken(child.jjtGetLastToken());
        }
    }

    default void addScope(IsScope scope) {
        addScope(singletonList(scope));
    }

    default void addScope(List scope) {
        // no need to do anything _right now_,
        // but in a future refactor, we will need to make
        // existing scope handling accept more than ChunkerIdent,
        // so we can use a generic source node as a scope
        // (e.g: `thing[1] = 2` has an array access scope, not an ident.
        throw new UnsupportedOperationException(getClass() +" must implement addScope(List)");
    }

    default void maybeDetach() {
        final Node parent = jjtGetParent();
        if (parent != null) {
            parent.removeChild(this);
        }
    }

    void removeChild(Node node);

    int indexOf(Node node);

    default DocumentRange.Builder asRange() {
        return DocumentRange.newBuilder()
                .setStart(jjtGetFirstToken().positionStart())
                .setEnd(jjtGetLastToken().positionEnd());
    }

    default boolean containsLines(int winStartLine, int winEndLine) {
        return jjtGetLastToken().endLine >= winEndLine && jjtGetFirstToken().beginLine <= winStartLine;
    }

    default boolean contains(Position pos) {
        final Position.Builder startPos = jjtGetFirstToken().positionStart();
        if (LspTools.greaterThan(startPos, pos)) {
            // if we start after this position, we don't contain it
            return false;
        }
        // we start before or after the query pos
        final Position.Builder endPos = jjtGetLastToken().positionEnd();
        // we contain the position if we also end after it.
        return LspTools.greaterOrEqual(endPos, pos);
    }

    default Token findToken(PositionOrBuilder requested) {
        final Position.Builder start = jjtGetFirstToken().positionStart();
        Token candidate = null;
        if (LspTools.lessOrEqual(start, requested)) {
            final Position.Builder end = jjtGetLastToken().positionEnd();
            if (LspTools.greaterOrEqual(end, requested)) {
                // we contain the position, iterate our own tokens to pick a winner.
                for (Token token : tokens(true)) {
                    if (token.containsPosition(requested)) {
                        candidate = token;
                    } else if (candidate != null) {
                        return candidate;
                    }
                }
            } else {
                // the position is after our end.
                for (Token token : jjtGetLastToken().to(null)) {
                    if (token.containsPosition(requested)) {
                        candidate = token;
                    } else if (candidate != null){
                        return candidate;
                    }
                    assert LspTools.lessThan(token.positionStart(), requested) : "Could not find " + requested + " after " + jjtGetLastToken();
                }
            }
        } else {
            // we start after requested, look backwards
            for (Token token : jjtGetFirstToken().toReverse(null)) {
                    if (token.containsPosition(requested)) {
                        candidate = token;
                        continue;
                    } else if (candidate != null) {
                        return candidate;
                    }
                    assert LspTools.greaterThan(token.positionEnd(), requested) : "Could not find " + requested + " before " + jjtGetFirstToken();
            }
        }
        if (candidate == null) {
            throw new IllegalArgumentException("Cannot find " + requested + " from " + this);
        }
        return candidate;
    }

    default int distanceTo(int offset) {
        int start = Math.abs(jjtGetFirstToken().startIndex - offset);
        int end = Math.abs(jjtGetLastToken().endIndex - offset);
        return Math.min(start, end);
    }
}
/* JavaCC - OriginalChecksum=8bee7910cdc54c0d060ca939cc170eb0 (do not edit this line) */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy