/* 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.
 */

#pragma once

#include "Recognizer.h"
#include "tree/ParseTreeListener.h"
#include "tree/ParseTree.h"
#include "TokenStream.h"
#include "TokenSource.h"
#include "misc/Interval.h"

namespace antlr4 {

  /// This is all the parsing support code essentially; most of it is error recovery stuff.
  class ANTLR4CPP_PUBLIC Parser : public Recognizer {
  public:

    class TraceListener : public tree::ParseTreeListener {
    public:
      TraceListener(Parser *outerInstance);
      virtual ~TraceListener();

      virtual void enterEveryRule(ParserRuleContext *ctx) override;
      virtual void visitTerminal(tree::TerminalNode *node) override;
      virtual void visitErrorNode(tree::ErrorNode *node) override;
      virtual void exitEveryRule(ParserRuleContext *ctx) override;

    private:
      Parser *const outerInstance;
    };

    class TrimToSizeListener : public tree::ParseTreeListener {
    public:
      static TrimToSizeListener INSTANCE;

      virtual ~TrimToSizeListener();

      virtual void enterEveryRule(ParserRuleContext *ctx) override;
      virtual void visitTerminal(tree::TerminalNode *node) override;
      virtual void visitErrorNode(tree::ErrorNode *node) override;
      virtual void exitEveryRule(ParserRuleContext *ctx) override;
    };

    Parser(TokenStream *input);
    virtual ~Parser();

    /// reset the parser's state
    virtual void reset();

    /// <summary>
    /// Match current input symbol against {@code ttype}. If the symbol type
    /// matches, <seealso cref="ANTLRErrorStrategy#reportMatch"/> and <seealso cref="#consume"/> are
    /// called to complete the match process.
    ///
    /// If the symbol type does not match,
    /// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is called on the current error
    /// strategy to attempt recovery. If <seealso cref="#getBuildParseTree"/> is
    /// {@code true} and the token index of the symbol returned by
    /// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is -1, the symbol is added to
    /// the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
    /// {@link ParserRuleContext#addErrorNode(ErrorNode)}.
    /// </summary>
    /// <param name="ttype"> the token type to match </param>
    /// <returns> the matched symbol </returns>
    /// <exception cref="RecognitionException"> if the current input symbol did not match
    /// {@code ttype} and the error strategy could not recover from the
    /// mismatched symbol </exception>
    virtual Token* match(size_t ttype);

    /// <summary>
    /// Match current input symbol as a wildcard. If the symbol type matches
    /// (i.e. has a value greater than 0), <seealso cref="ANTLRErrorStrategy#reportMatch"/>
    /// and <seealso cref="#consume"/> are called to complete the match process.
    /// <p/>
    /// If the symbol type does not match,
    /// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is called on the current error
    /// strategy to attempt recovery. If <seealso cref="#getBuildParseTree"/> is
    /// {@code true} and the token index of the symbol returned by
    /// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is -1, the symbol is added to
    /// the parse tree by calling <seealso cref="ParserRuleContext#addErrorNode"/>.
    /// </summary>
    /// <returns> the matched symbol </returns>
    /// <exception cref="RecognitionException"> if the current input symbol did not match
    /// a wildcard and the error strategy could not recover from the mismatched
    /// symbol </exception>
    virtual Token* matchWildcard();

    /// <summary>
    /// Track the <seealso cref="ParserRuleContext"/> objects during the parse and hook
    /// them up using the <seealso cref="ParserRuleContext#children"/> list so that it
    /// forms a parse tree. The <seealso cref="ParserRuleContext"/> returned from the start
    /// rule represents the root of the parse tree.
    /// <p/>
    /// Note that if we are not building parse trees, rule contexts only point
    /// upwards. When a rule exits, it returns the context but that gets garbage
    /// collected if nobody holds a reference. It points upwards but nobody
    /// points at it.
    /// <p/>
    /// When we build parse trees, we are adding all of these contexts to
    /// <seealso cref="ParserRuleContext#children"/> list. Contexts are then not candidates
    /// for garbage collection.
    /// </summary>
    virtual void setBuildParseTree(bool buildParseTrees);

    /// <summary>
    /// Gets whether or not a complete parse tree will be constructed while
    /// parsing. This property is {@code true} for a newly constructed parser.
    /// </summary>
    /// <returns> {@code true} if a complete parse tree will be constructed while
    /// parsing, otherwise {@code false} </returns>
    virtual bool getBuildParseTree();

    /// <summary>
    /// Trim the internal lists of the parse tree during parsing to conserve memory.
    /// This property is set to {@code false} by default for a newly constructed parser.
    /// </summary>
    /// <param name="trimParseTrees"> {@code true} to trim the capacity of the <seealso cref="ParserRuleContext#children"/>
    /// list to its size after a rule is parsed. </param>
    virtual void setTrimParseTree(bool trimParseTrees);

    /// <returns> {@code true} if the <seealso cref="ParserRuleContext#children"/> list is trimmed
    /// using the default <seealso cref="Parser.TrimToSizeListener"/> during the parse process. </returns>
    virtual bool getTrimParseTree();

    virtual std::vector<tree::ParseTreeListener *> getParseListeners();

    /// <summary>
    /// Registers {@code listener} to receive events during the parsing process.
    /// <p/>
    /// To support output-preserving grammar transformations (including but not
    /// limited to left-recursion removal, automated left-factoring, and
    /// optimized code generation), calls to listener methods during the parse
    /// may differ substantially from calls made by
    /// <seealso cref="ParseTreeWalker#DEFAULT"/> used after the parse is complete. In
    /// particular, rule entry and exit events may occur in a different order
    /// during the parse than after the parser. In addition, calls to certain
    /// rule entry methods may be omitted.
    /// <p/>
    /// With the following specific exceptions, calls to listener events are
    /// <em>deterministic</em>, i.e. for identical input the calls to listener
    /// methods will be the same.
    ///
    /// <ul>
    /// <li>Alterations to the grammar used to generate code may change the
    /// behavior of the listener calls.</li>
    /// <li>Alterations to the command line options passed to ANTLR 4 when
    /// generating the parser may change the behavior of the listener calls.</li>
    /// <li>Changing the version of the ANTLR Tool used to generate the parser
    /// may change the behavior of the listener calls.</li>
    /// </ul>
    /// </summary>
    /// <param name="listener"> the listener to add
    /// </param>
    /// <exception cref="NullPointerException"> if {@code} listener is {@code null} </exception>
    virtual void addParseListener(tree::ParseTreeListener *listener);

    /// <summary>
    /// Remove {@code listener} from the list of parse listeners.
    /// <p/>
    /// If {@code listener} is {@code null} or has not been added as a parse
    /// listener, this method does nothing.
    /// </summary>
    /// <seealso cref= #addParseListener
    /// </seealso>
    /// <param name="listener"> the listener to remove </param>
    virtual void removeParseListener(tree::ParseTreeListener *listener);

    /// <summary>
    /// Remove all parse listeners.
    /// </summary>
    /// <seealso cref= #addParseListener </seealso>
    virtual void removeParseListeners();

    /// <summary>
    /// Notify any parse listeners of an enter rule event.
    /// </summary>
    /// <seealso cref= #addParseListener </seealso>
    virtual void triggerEnterRuleEvent();

    /// <summary>
    /// Notify any parse listeners of an exit rule event.
    /// </summary>
    /// <seealso cref= #addParseListener </seealso>
    virtual void triggerExitRuleEvent();

    /// <summary>
    /// Gets the number of syntax errors reported during parsing. This value is
    /// incremented each time <seealso cref="#notifyErrorListeners"/> is called.
    /// </summary>
    /// <seealso cref= #notifyErrorListeners </seealso>
    virtual size_t getNumberOfSyntaxErrors();

    virtual TokenFactory<CommonToken>* getTokenFactory() override;

    /// <summary>
    /// Tell our token source and error strategy about a new way to create tokens. </summary>
    template<typename T1>
    void setTokenFactory(TokenFactory<T1> *factory)  {
      _input->getTokenSource()->setTokenFactory(factory);
    }

    /// The ATN with bypass alternatives is expensive to create so we create it
    /// lazily. The ATN is owned by us.
    virtual const atn::ATN& getATNWithBypassAlts();

    /// <summary>
    /// The preferred method of getting a tree pattern. For example, here's a
    /// sample use:
    ///
    /// <pre>
    /// ParseTree t = parser.expr();
    /// ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
    /// ParseTreeMatch m = p.match(t);
    /// String id = m.get("ID");
    /// </pre>
    /// </summary>
    virtual tree::pattern::ParseTreePattern compileParseTreePattern(const std::string &pattern, int patternRuleIndex);

    /// <summary>
    /// The same as <seealso cref="#compileParseTreePattern(String, int)"/> but specify a
    /// <seealso cref="Lexer"/> rather than trying to deduce it from this parser.
    /// </summary>
    virtual tree::pattern::ParseTreePattern compileParseTreePattern(const std::string &pattern, int patternRuleIndex,
                                                                    Lexer *lexer);

    virtual Ref<ANTLRErrorStrategy> getErrorHandler();
    virtual void setErrorHandler(Ref<ANTLRErrorStrategy> const& handler);

    virtual IntStream* getInputStream() override;
    void setInputStream(IntStream *input) override;

    virtual TokenStream* getTokenStream();

    /// Set the token stream and reset the parser.
    virtual void setTokenStream(TokenStream *input);

    /// <summary>
    /// Match needs to return the current input symbol, which gets put
    ///  into the label for the associated token ref; e.g., x=ID.
    /// </summary>
    virtual Token* getCurrentToken();

    void notifyErrorListeners(const std::string &msg);

    virtual void notifyErrorListeners(Token *offendingToken, const std::string &msg, std::exception_ptr e);

    /// Consume and return the <seealso cref="#getCurrentToken current symbol"/>.
    /// <p/>
    /// E.g., given the following input with {@code A} being the current
    /// lookahead symbol, this function moves the cursor to {@code B} and returns
    /// {@code A}.
    ///
    /// <pre>
    ///  A B
    ///  ^
    /// </pre>
    ///
    /// If the parser is not in error recovery mode, the consumed symbol is added
    /// to the parse tree using <seealso cref="ParserRuleContext#addChild(TerminalNode)"/>, and
    /// <seealso cref="ParseTreeListener#visitTerminal"/> is called on any parse listeners.
    /// If the parser <em>is</em> in error recovery mode, the consumed symbol is
    /// added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then
    /// {@link ParserRuleContext#addErrorNode(ErrorNode)} and
    /// <seealso cref="ParseTreeListener#visitErrorNode"/> is called on any parse
    /// listeners.
    virtual Token* consume();

    /// Always called by generated parsers upon entry to a rule. Access field
    /// <seealso cref="#_ctx"/> get the current context.
    virtual void enterRule(ParserRuleContext *localctx, size_t state, size_t ruleIndex);

    void exitRule();

    virtual void enterOuterAlt(ParserRuleContext *localctx, size_t altNum);

    /**
     * Get the precedence level for the top-most precedence rule.
     *
     * @return The precedence level for the top-most precedence rule, or -1 if
     * the parser context is not nested within a precedence rule.
     */
    int getPrecedence() const;

    /// @deprecated Use
    /// <seealso cref="#enterRecursionRule(ParserRuleContext, int, int, int)"/> instead.
    virtual void enterRecursionRule(ParserRuleContext *localctx, size_t ruleIndex);
    virtual void enterRecursionRule(ParserRuleContext *localctx, size_t state, size_t ruleIndex, int precedence);

    /** Like {@link #enterRule} but for recursive rules.
     *  Make the current context the child of the incoming localctx.
     */
    virtual void pushNewRecursionContext(ParserRuleContext *localctx, size_t state, size_t ruleIndex);
    virtual void unrollRecursionContexts(ParserRuleContext *parentctx);
    virtual ParserRuleContext* getInvokingContext(size_t ruleIndex);
    virtual ParserRuleContext* getContext();
    virtual void setContext(ParserRuleContext *ctx);
    virtual bool precpred(RuleContext *localctx, int precedence) override;
    virtual bool inContext(const std::string &context);

    /// <summary>
    /// Checks whether or not {@code symbol} can follow the current state in the
    /// ATN. The behavior of this method is equivalent to the following, but is
    /// implemented such that the complete context-sensitive follow set does not
    /// need to be explicitly constructed.
    ///
    /// <pre>
    /// return getExpectedTokens().contains(symbol);
    /// </pre>
    /// </summary>
    /// <param name="symbol"> the symbol type to check </param>
    /// <returns> {@code true} if {@code symbol} can follow the current state in
    /// the ATN, otherwise {@code false}. </returns>
    virtual bool isExpectedToken(size_t symbol);

    bool isMatchedEOF() const;

    /// <summary>
    /// Computes the set of input symbols which could follow the current parser
    /// state and context, as given by <seealso cref="#getState"/> and <seealso cref="#getContext"/>,
    /// respectively.
    /// </summary>
    /// <seealso cref= ATN#getExpectedTokens(int, RuleContext) </seealso>
    virtual misc::IntervalSet getExpectedTokens();

    virtual misc::IntervalSet getExpectedTokensWithinCurrentRule();

    /// Get a rule's index (i.e., {@code RULE_ruleName} field) or INVALID_INDEX if not found.
    virtual size_t getRuleIndex(const std::string &ruleName);

    virtual ParserRuleContext* getRuleContext();

    /// <summary>
    /// Return List&lt;String&gt; of the rule names in your parser instance
    ///  leading up to a call to the current rule.  You could override if
    ///  you want more details such as the file/line info of where
    ///  in the ATN a rule is invoked.
    ///
    ///  This is very useful for error messages.
    /// </summary>
    virtual std::vector<std::string> getRuleInvocationStack();

    virtual std::vector<std::string> getRuleInvocationStack(RuleContext *p);

    /// <summary>
    /// For debugging and other purposes. </summary>
    virtual std::vector<std::string> getDFAStrings();

    /// <summary>
    /// For debugging and other purposes. </summary>
    virtual void dumpDFA();

    virtual std::string getSourceName();

    atn::ParseInfo getParseInfo() const;

    /**
     * @since 4.3
     */
    void setProfile(bool profile);

    /// <summary>
    /// During a parse is sometimes useful to listen in on the rule entry and exit
    ///  events as well as token matches. This is for quick and dirty debugging.
    /// </summary>
    virtual void setTrace(bool trace);

    /**
     * Gets whether a {@link TraceListener} is registered as a parse listener
     * for the parser.
     *
     * @see #setTrace(boolean)
     */
    bool isTrace() const;

    tree::ParseTreeTracker& getTreeTracker() { return _tracker; }

    /** How to create a token leaf node associated with a parent.
     *  Typically, the terminal node to create is not a function of the parent
     *  but this method must still set the parent pointer of the terminal node
     *  returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
     *  set the parent pointer, but the parent pointer is implementation dependent
     *  and currently there is no setParent() in {@link TerminalNode} (and can't
     *  add method in Java 1.7 without breaking backward compatibility).
     *
     * @since 4.7
     */
    tree::TerminalNode *createTerminalNode(Token *t);

    /** How to create an error node, given a token, associated with a parent.
       *  Typically, the error node to create is not a function of the parent
       *  but this method must still set the parent pointer of the terminal node
       *  returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
       *  set the parent pointer, but the parent pointer is implementation dependent
       *  and currently there is no setParent() in {@link ErrorNode} (and can't
       *  add method in Java 1.7 without breaking backward compatibility).
       *
       * @since 4.7
       */
    tree::ErrorNode *createErrorNode(Token *t);

  protected:
    /// The ParserRuleContext object for the currently executing rule.
    /// This is always non-null during the parsing process.
    // ml: this is one of the contexts tracked in _allocatedContexts.
    ParserRuleContext *_ctx;

    /// The error handling strategy for the parser. The default is DefaultErrorStrategy.
    /// See also getErrorHandler.
    Ref<ANTLRErrorStrategy> _errHandler;

    /// <summary>
    /// The input stream.
    /// </summary>
    /// <seealso cref= #getInputStream </seealso>
    /// <seealso cref= #setInputStream </seealso>
    TokenStream *_input;

    std::vector<int> _precedenceStack;

    /// <summary>
    /// Specifies whether or not the parser should construct a parse tree during
    /// the parsing process. The default value is {@code true}.
    /// </summary>
    /// <seealso cref= #getBuildParseTree </seealso>
    /// <seealso cref= #setBuildParseTree </seealso>
    bool _buildParseTrees;

    /// The list of <seealso cref="ParseTreeListener"/> listeners registered to receive
    /// events during the parse.
    /// <seealso cref= #addParseListener </seealso>
    std::vector<tree::ParseTreeListener *> _parseListeners;

    /// <summary>
    /// The number of syntax errors reported during parsing. This value is
    /// incremented each time <seealso cref="#notifyErrorListeners"/> is called.
    /// </summary>
    size_t _syntaxErrors;

    /** Indicates parser has match()ed EOF token. See {@link #exitRule()}. */
    bool _matchedEOF;

    virtual void addContextToParseTree();

    // All rule contexts created during a parse run. This is cleared when calling reset().
    tree::ParseTreeTracker _tracker;

  private:
    /// When setTrace(true) is called, a reference to the
    /// TraceListener is stored here so it can be easily removed in a
    /// later call to setTrace(false). The listener itself is
    /// implemented as a parser listener so this field is not directly used by
    /// other parser methods.
    TraceListener *_tracer;

    void InitializeInstanceFields();
  };

} // namespace antlr4
