blob: 4bc95bd7e26dbcf650bf63f52fe3946c89300079 [file] [log] [blame]
/*
* [The "BSD licence"]
* Copyright (c) 2005-2008 Terence Parr
* All rights reserved.
*
* Conversion to C#:
* Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace Antlr.Runtime.Debug {
/** <summary>All debugging events that a recognizer can trigger.</summary>
*
* <remarks>
* I did not create a separate AST debugging interface as it would create
* lots of extra classes and DebugParser has a dbg var defined, which makes
* it hard to change to ASTDebugEventListener. I looked hard at this issue
* and it is easier to understand as one monolithic event interface for all
* possible events. Hopefully, adding ST debugging stuff won't be bad. Leave
* for future. 4/26/2006.
* </remarks>
*/
public interface IDebugEventListener {
void Initialize();
/** <summary>
* The parser has just entered a rule. No decision has been made about
* which alt is predicted. This is fired AFTER init actions have been
* executed. Attributes are defined and available etc...
* The grammarFileName allows composite grammars to jump around among
* multiple grammar files.
* </summary>
*/
void EnterRule(string grammarFileName, string ruleName);
/** <summary>
* Because rules can have lots of alternatives, it is very useful to
* know which alt you are entering. This is 1..n for n alts.
* </summary>
*/
void EnterAlt(int alt);
/** <summary>
* This is the last thing executed before leaving a rule. It is
* executed even if an exception is thrown. This is triggered after
* error reporting and recovery have occurred (unless the exception is
* not caught in this rule). This implies an "exitAlt" event.
* The grammarFileName allows composite grammars to jump around among
* multiple grammar files.
* </summary>
*/
void ExitRule(string grammarFileName, string ruleName);
/** <summary>Track entry into any (...) subrule other EBNF construct</summary> */
void EnterSubRule(int decisionNumber);
void ExitSubRule(int decisionNumber);
/** <summary>
* Every decision, fixed k or arbitrary, has an enter/exit event
* so that a GUI can easily track what LT/consume events are
* associated with prediction. You will see a single enter/exit
* subrule but multiple enter/exit decision events, one for each
* loop iteration.
* </summary>
*/
void EnterDecision(int decisionNumber, bool couldBacktrack);
void ExitDecision(int decisionNumber);
/** <summary>
* An input token was consumed; matched by any kind of element.
* Trigger after the token was matched by things like match(), matchAny().
* </summary>
*/
void ConsumeToken(IToken t);
/** <summary>
* An off-channel input token was consumed.
* Trigger after the token was matched by things like match(), matchAny().
* (unless of course the hidden token is first stuff in the input stream).
* </summary>
*/
void ConsumeHiddenToken(IToken t);
/** <summary>
* Somebody (anybody) looked ahead. Note that this actually gets
* triggered by both LA and LT calls. The debugger will want to know
* which Token object was examined. Like consumeToken, this indicates
* what token was seen at that depth. A remote debugger cannot look
* ahead into a file it doesn't have so LT events must pass the token
* even if the info is redundant.
* </summary>
*/
void LT(int i, IToken t);
/** <summary>
* The parser is going to look arbitrarily ahead; mark this location,
* the token stream's marker is sent in case you need it.
* </summary>
*/
void Mark(int marker);
/** <summary>
* After an arbitrairly long lookahead as with a cyclic DFA (or with
* any backtrack), this informs the debugger that stream should be
* rewound to the position associated with marker.
* </summary>
*/
void Rewind(int marker);
/** <summary>
* Rewind to the input position of the last marker.
* Used currently only after a cyclic DFA and just
* before starting a sem/syn predicate to get the
* input position back to the start of the decision.
* Do not "pop" the marker off the state. mark(i)
* and rewind(i) should balance still.
* </summary>
*/
void Rewind();
void BeginBacktrack(int level);
void EndBacktrack(int level, bool successful);
/** <summary>
* To watch a parser move through the grammar, the parser needs to
* inform the debugger what line/charPos it is passing in the grammar.
* For now, this does not know how to switch from one grammar to the
* other and back for island grammars etc...
* </summary>
*
* <remarks>
* This should also allow breakpoints because the debugger can stop
* the parser whenever it hits this line/pos.
* </remarks>
*/
void Location(int line, int pos);
/** <summary>
* A recognition exception occurred such as NoViableAltException. I made
* this a generic event so that I can alter the exception hierachy later
* without having to alter all the debug objects.
* </summary>
*
* <remarks>
* Upon error, the stack of enter rule/subrule must be properly unwound.
* If no viable alt occurs it is within an enter/exit decision, which
* also must be rewound. Even the rewind for each mark must be unwount.
* In the Java target this is pretty easy using try/finally, if a bit
* ugly in the generated code. The rewind is generated in DFA.predict()
* actually so no code needs to be generated for that. For languages
* w/o this "finally" feature (C++?), the target implementor will have
* to build an event stack or something.
*
* Across a socket for remote debugging, only the RecognitionException
* data fields are transmitted. The token object or whatever that
* caused the problem was the last object referenced by LT. The
* immediately preceding LT event should hold the unexpected Token or
* char.
*
* Here is a sample event trace for grammar:
*
* b : C ({;}A|B) // {;} is there to prevent A|B becoming a set
* | D
* ;
*
* The sequence for this rule (with no viable alt in the subrule) for
* input 'c c' (there are 3 tokens) is:
*
* commence
* LT(1)
* enterRule b
* location 7 1
* enter decision 3
* LT(1)
* exit decision 3
* enterAlt1
* location 7 5
* LT(1)
* consumeToken [c/<4>,1:0]
* location 7 7
* enterSubRule 2
* enter decision 2
* LT(1)
* LT(1)
* recognitionException NoViableAltException 2 1 2
* exit decision 2
* exitSubRule 2
* beginResync
* LT(1)
* consumeToken [c/<4>,1:1]
* LT(1)
* endResync
* LT(-1)
* exitRule b
* terminate
* </remarks>
*/
void RecognitionException(RecognitionException e);
/** <summary>
* Indicates the recognizer is about to consume tokens to resynchronize
* the parser. Any consume events from here until the recovered event
* are not part of the parse--they are dead tokens.
* </summary>
*/
void BeginResync();
/** <summary>
* Indicates that the recognizer has finished consuming tokens in order
* to resychronize. There may be multiple beginResync/endResync pairs
* before the recognizer comes out of errorRecovery mode (in which
* multiple errors are suppressed). This will be useful
* in a gui where you want to probably grey out tokens that are consumed
* but not matched to anything in grammar. Anything between
* a beginResync/endResync pair was tossed out by the parser.
* </summary>
*/
void EndResync();
/** <summary>A semantic predicate was evaluate with this result and action text</summary> */
void SemanticPredicate(bool result, string predicate);
/** <summary>
* Announce that parsing has begun. Not technically useful except for
* sending events over a socket. A GUI for example will launch a thread
* to connect and communicate with a remote parser. The thread will want
* to notify the GUI when a connection is made. ANTLR parsers
* trigger this upon entry to the first rule (the ruleLevel is used to
* figure this out).
* </summary>
*/
void Commence();
/** <summary>
* Parsing is over; successfully or not. Mostly useful for telling
* remote debugging listeners that it's time to quit. When the rule
* invocation level goes to zero at the end of a rule, we are done
* parsing.
* </summary>
*/
void Terminate();
#region Tree Parsing
/** <summary>
* Input for a tree parser is an AST, but we know nothing for sure
* about a node except its type and text (obtained from the adaptor).
* This is the analog of the consumeToken method. Again, the ID is
* the hashCode usually of the node so it only works if hashCode is
* not implemented. If the type is UP or DOWN, then
* the ID is not really meaningful as it's fixed--there is
* just one UP node and one DOWN navigation node.
* </summary>
*
* <param name="t" />
*/
void ConsumeNode(object t);
/** <summary>
* The tree parser lookedahead. If the type is UP or DOWN,
* then the ID is not really meaningful as it's fixed--there is
* just one UP node and one DOWN navigation node.
* </summary>
*/
void LT(int i, object t);
#endregion
#region AST Events
/** <summary>
* A nil was created (even nil nodes have a unique ID...
* they are not "null" per se). As of 4/28/2006, this
* seems to be uniquely triggered when starting a new subtree
* such as when entering a subrule in automatic mode and when
* building a tree in rewrite mode.
* </summary>
*
* <remarks>
* If you are receiving this event over a socket via
* RemoteDebugEventSocketListener then only t.ID is set.
* </remarks>
*/
void NilNode(object t);
/** <summary>
* Upon syntax error, recognizers bracket the error with an error node
* if they are building ASTs.
* </summary>
*
* <param name="t"/>
*/
void ErrorNode(object t);
/** <summary>Announce a new node built from token elements such as type etc...</summary>
*
* <remarks>
* If you are receiving this event over a socket via
* RemoteDebugEventSocketListener then only t.ID, type, text are
* set.
* </remarks>
*/
void CreateNode(object t);
/** <summary>Announce a new node built from an existing token.</summary>
*
* <remarks>
* If you are receiving this event over a socket via
* RemoteDebugEventSocketListener then only node.ID and token.tokenIndex
* are set.
* </remarks>
*/
void CreateNode(object node, IToken token);
/** <summary>Make a node the new root of an existing root. See</summary>
*
* <remarks>
* Note: the newRootID parameter is possibly different
* than the TreeAdaptor.becomeRoot() newRoot parameter.
* In our case, it will always be the result of calling
* TreeAdaptor.becomeRoot() and not root_n or whatever.
*
* The listener should assume that this event occurs
* only when the current subrule (or rule) subtree is
* being reset to newRootID.
*
* If you are receiving this event over a socket via
* RemoteDebugEventSocketListener then only IDs are set.
* </remarks>
*
* <seealso cref="Antlr.Runtime.Tree.TreeAdaptor.becomeRoot()"/>
*/
void BecomeRoot(object newRoot, object oldRoot);
/** <summary>Make childID a child of rootID.</summary>
*
* <remarks>
* If you are receiving this event over a socket via
* RemoteDebugEventSocketListener then only IDs are set.
* </remarks>
*
* <seealso cref="Antlr.Runtime.Tree.TreeAdaptor.addChild()"/>
*/
void AddChild(object root, object child);
/** <summary>Set the token start/stop token index for a subtree root or node.</summary>
*
* <remarks>
* If you are receiving this event over a socket via
* RemoteDebugEventSocketListener then only t.ID is set.
* </remarks>
*/
void SetTokenBoundaries(object t, int tokenStartIndex, int tokenStopIndex);
#endregion
}
}