org.antlr.v4.runtime.ParserRuleContext.java Source code

Java tutorial

Introduction

Here is the source code for org.antlr.v4.runtime.ParserRuleContext.java

Source

/*
 * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
 * Use of this file is governed by the BSD 3-clause license that
 * can be found in the LICENSE.txt file in the project root.
 */
package org.antlr.v4.runtime;

import org.antlr.v4.runtime.misc.Interval;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ErrorNodeImpl;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.antlr.v4.runtime.tree.TerminalNodeImpl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/** A rule invocation record for parsing.
 *
 *  Contains all of the information about the current rule not stored in the
 *  RuleContext. It handles parse tree children list, Any ATN state
 *  tracing, and the default values available for rule invocations:
 *  start, stop, rule index, current alt number.
 *
 *  Subclasses made for each rule and grammar track the parameters,
 *  return values, locals, and labels specific to that rule. These
 *  are the objects that are returned from rules.
 *
 *  Note text is not an actual field of a rule return value; it is computed
 *  from start and stop using the input stream's toString() method.  I
 *  could add a ctor to this so that we can pass in and store the input
 *  stream, but I'm not sure we want to do that.  It would seem to be undefined
 *  to get the .text property anyway if the rule matches tokens from multiple
 *  input streams.
 *
 *  I do not use getters for fields of objects that are used simply to
 *  group values such as this aggregate.  The getters/setters are there to
 *  satisfy the superclass interface.
 */
public class ParserRuleContext extends RuleContext {
    /** If we are debugging or building a parse tree for a visitor,
     *  we need to track all of the tokens and rule invocations associated
     *  with this rule's context. This is empty for parsing w/o tree constr.
     *  operation because we don't the need to track the details about
     *  how we parse this rule.
     */
    public List<ParseTree> children;

    /** For debugging/tracing purposes, we want to track all of the nodes in
     *  the ATN traversed by the parser for a particular rule.
     *  This list indicates the sequence of ATN nodes used to match
     *  the elements of the children list. This list does not include
     *  ATN nodes and other rules used to match rule invocations. It
     *  traces the rule invocation node itself but nothing inside that
     *  other rule's ATN submachine.
     *
     *  There is NOT a one-to-one correspondence between the children and
     *  states list. There are typically many nodes in the ATN traversed
     *  for each element in the children list. For example, for a rule
     *  invocation there is the invoking state and the following state.
     *
     *  The parser setState() method updates field s and adds it to this list
     *  if we are debugging/tracing.
     *
     *  This does not trace states visited during prediction.
     */
    //   public List<Integer> states;

    public Token start, stop;

    /**
     * The exception that forced this rule to return. If the rule successfully
     * completed, this is {@code null}.
     */
    public RecognitionException exception;

    public ParserRuleContext() {
    }

    /** COPY a ctx (I'm deliberately not using copy constructor) to avoid
     *  confusion with creating node with parent. Does not copy children
     *  (except error leaves).
     *
     *  This is used in the generated parser code to flip a generic XContext
     *  node for rule X to a YContext for alt label Y. In that sense, it is
     *  not really a generic copy function.
     *
     *  If we do an error sync() at start of a rule, we might add error nodes
     *  to the generic XContext so this function must copy those nodes to
     *  the YContext as well else they are lost!
     */
    public void copyFrom(ParserRuleContext ctx) {
        this.parent = ctx.parent;
        this.invokingState = ctx.invokingState;

        this.start = ctx.start;
        this.stop = ctx.stop;

        // copy any error nodes to alt label node
        if (ctx.children != null) {
            this.children = new ArrayList<>();
            // reset parent pointer for any error nodes
            for (ParseTree child : ctx.children) {
                if (child instanceof ErrorNode) {
                    addChild((ErrorNode) child);
                }
            }
        }
    }

    public ParserRuleContext(ParserRuleContext parent, int invokingStateNumber) {
        super(parent, invokingStateNumber);
    }

    // Double dispatch methods for listeners

    public void enterRule(ParseTreeListener listener) {
    }

    public void exitRule(ParseTreeListener listener) {
    }

    /** Add a parse tree node to this as a child.  Works for
     *  internal and leaf nodes. Does not set parent link;
     *  other add methods must do that. Other addChild methods
     *  call this.
     *
     *  We cannot set the parent pointer of the incoming node
     *  because the existing interfaces do not have a setParent()
     *  method and I don't want to break backward compatibility for this.
     *
     *  @since 4.7
     */
    public <T extends ParseTree> T addAnyChild(T t) {
        if (children == null)
            children = new ArrayList<>();
        children.add(t);
        return t;
    }

    public RuleContext addChild(RuleContext ruleInvocation) {
        return addAnyChild(ruleInvocation);
    }

    /** Add a token leaf node child and force its parent to be this node. */
    public TerminalNode addChild(TerminalNode t) {
        t.setParent(this);
        return addAnyChild(t);
    }

    /** Add an error node child and force its parent to be this node.
     *
     * @since 4.7
     */
    public ErrorNode addErrorNode(ErrorNode errorNode) {
        errorNode.setParent(this);
        return addAnyChild(errorNode);
    }

    /** Add a child to this node based upon matchedToken. It
     *  creates a TerminalNodeImpl rather than using
     *  {@link Parser#createTerminalNode(ParserRuleContext, Token)}. I'm leaving this
      *  in for compatibility but the parser doesn't use this anymore.
     */
    @Deprecated
    public TerminalNode addChild(Token matchedToken) {
        TerminalNodeImpl t = new TerminalNodeImpl(matchedToken);
        addAnyChild(t);
        t.setParent(this);
        return t;
    }

    /** Add a child to this node based upon badToken.  It
     *  creates a ErrorNodeImpl rather than using
     *  {@link Parser#createErrorNode(ParserRuleContext, Token)}. I'm leaving this
     *  in for compatibility but the parser doesn't use this anymore.
     */
    @Deprecated
    public ErrorNode addErrorNode(Token badToken) {
        ErrorNodeImpl t = new ErrorNodeImpl(badToken);
        addAnyChild(t);
        t.setParent(this);
        return t;
    }

    //   public void trace(int s) {
    //      if ( states==null ) states = new ArrayList<Integer>();
    //      states.add(s);
    //   }

    /** Used by enterOuterAlt to toss out a RuleContext previously added as
     *  we entered a rule. If we have # label, we will need to remove
     *  generic ruleContext object.
     */
    public void removeLastChild() {
        if (children != null) {
            children.remove(children.size() - 1);
        }
    }

    @Override
    /** Override to make type more specific */
    public ParserRuleContext getParent() {
        return (ParserRuleContext) super.getParent();
    }

    @Override
    public ParseTree getChild(int i) {
        return children != null && i >= 0 && i < children.size() ? children.get(i) : null;
    }

    public <T extends ParseTree> T getChild(Class<? extends T> ctxType, int i) {
        if (children == null || i < 0 || i >= children.size()) {
            return null;
        }

        int j = -1; // what element have we found with ctxType?
        for (ParseTree o : children) {
            if (ctxType.isInstance(o)) {
                j++;
                if (j == i) {
                    return ctxType.cast(o);
                }
            }
        }
        return null;
    }

    public TerminalNode getToken(int ttype, int i) {
        if (children == null || i < 0 || i >= children.size()) {
            return null;
        }

        int j = -1; // what token with ttype have we found?
        for (ParseTree o : children) {
            if (o instanceof TerminalNode) {
                TerminalNode tnode = (TerminalNode) o;
                Token symbol = tnode.getSymbol();
                if (symbol.getType() == ttype) {
                    j++;
                    if (j == i) {
                        return tnode;
                    }
                }
            }
        }

        return null;
    }

    public List<TerminalNode> getTokens(int ttype) {
        if (children == null) {
            return Collections.emptyList();
        }

        List<TerminalNode> tokens = null;
        for (ParseTree o : children) {
            if (o instanceof TerminalNode) {
                TerminalNode tnode = (TerminalNode) o;
                Token symbol = tnode.getSymbol();
                if (symbol.getType() == ttype) {
                    if (tokens == null) {
                        tokens = new ArrayList<TerminalNode>();
                    }
                    tokens.add(tnode);
                }
            }
        }

        if (tokens == null) {
            return Collections.emptyList();
        }

        return tokens;
    }

    public <T extends ParserRuleContext> T getRuleContext(Class<? extends T> ctxType, int i) {
        return getChild(ctxType, i);
    }

    public <T extends ParserRuleContext> List<T> getRuleContexts(Class<? extends T> ctxType) {
        if (children == null) {
            return Collections.emptyList();
        }

        List<T> contexts = null;
        for (ParseTree o : children) {
            if (ctxType.isInstance(o)) {
                if (contexts == null) {
                    contexts = new ArrayList<T>();
                }

                contexts.add(ctxType.cast(o));
            }
        }

        if (contexts == null) {
            return Collections.emptyList();
        }

        return contexts;
    }

    @Override
    public int getChildCount() {
        return children != null ? children.size() : 0;
    }

    @Override
    public Interval getSourceInterval() {
        if (start == null) {
            return Interval.INVALID;
        }
        if (stop == null || stop.getTokenIndex() < start.getTokenIndex()) {
            return Interval.of(start.getTokenIndex(), start.getTokenIndex() - 1); // empty
        }
        return Interval.of(start.getTokenIndex(), stop.getTokenIndex());
    }

    /**
     * Get the initial token in this context.
     * Note that the range from start to stop is inclusive, so for rules that do not consume anything
     * (for example, zero length or error productions) this token may exceed stop.
     */
    public Token getStart() {
        return start;
    }

    /**
     * Get the final token in this context.
     * Note that the range from start to stop is inclusive, so for rules that do not consume anything
     * (for example, zero length or error productions) this token may precede start.
     */
    public Token getStop() {
        return stop;
    }

    /** Used for rule context info debugging during parse-time, not so much for ATN debugging */
    public String toInfoString(Parser recognizer) {
        List<String> rules = recognizer.getRuleInvocationStack(this);
        Collections.reverse(rules);
        return "ParserRuleContext" + rules + "{" + "start=" + start + ", stop=" + stop + '}';
    }
}