bitmark-grammar
Version:
934 lines (831 loc) • 28.7 kB
text/typescript
/*!
* Copyright 2016 The ANTLR Project. All rights reserved.
* Licensed under the BSD-3-Clause license. See LICENSE file in the project root for license information.
*/
// ConvertTo-TS run at 2016-10-04T11:26:52.4399193-07:00
import * as assert from "assert";
import * as Utils from "./misc/Utils";
import { ANTLRErrorListener } from "./ANTLRErrorListener";
import { ANTLRErrorStrategy } from "./ANTLRErrorStrategy";
import { ATN } from "./atn/ATN";
import { ATNDeserializationOptions } from "./atn/ATNDeserializationOptions";
import { ATNDeserializer } from "./atn/ATNDeserializer";
import { ATNSimulator } from "./atn/ATNSimulator";
import { ATNState } from "./atn/ATNState";
import { DefaultErrorStrategy } from "./DefaultErrorStrategy";
import { DFA } from "./dfa/DFA";
import { ErrorNode } from "./tree/ErrorNode";
import { IntegerStack } from "./misc/IntegerStack";
import { IntervalSet } from "./misc/IntervalSet";
import { IntStream } from "./IntStream";
import { Lexer } from "./Lexer";
import { Override, NotNull, Nullable } from "./Decorators";
import { ParseInfo } from "./atn/ParseInfo";
import { ParserATNSimulator } from "./atn/ParserATNSimulator";
import { ParserErrorListener } from "./ParserErrorListener";
import { ParserRuleContext } from "./ParserRuleContext";
import { ParseTreeListener } from "./tree/ParseTreeListener";
import { ParseTreePattern } from "./tree/pattern/ParseTreePattern";
import { ProxyParserErrorListener } from "./ProxyParserErrorListener";
import { RecognitionException } from "./RecognitionException";
import { Recognizer } from "./Recognizer";
import { RuleContext } from "./RuleContext";
import { RuleTransition } from "./atn/RuleTransition";
import { TerminalNode } from "./tree/TerminalNode";
import { Token } from "./Token";
import { TokenFactory } from "./TokenFactory";
import { TokenSource } from "./TokenSource";
import { TokenStream } from "./TokenStream";
class TraceListener implements ParseTreeListener {
constructor(private ruleNames: string[], private tokenStream: TokenStream) {
}
public enterEveryRule(ctx: ParserRuleContext): void {
console.log("enter " + this.ruleNames[ctx.ruleIndex] +
", LT(1)=" + this.tokenStream.LT(1).text);
}
public exitEveryRule(ctx: ParserRuleContext): void {
console.log("exit " + this.ruleNames[ctx.ruleIndex] +
", LT(1)=" + this.tokenStream.LT(1).text);
}
public visitErrorNode(node: ErrorNode): void {
// intentionally empty
}
public visitTerminal(node: TerminalNode): void {
let parent = node.parent!.ruleContext;
let token: Token = node.symbol;
console.log("consume " + token + " rule " + this.ruleNames[parent.ruleIndex]);
}
}
/** This is all the parsing support code essentially; most of it is error recovery stuff. */
export abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
/**
* This field maps from the serialized ATN string to the deserialized {@link ATN} with
* bypass alternatives.
*
* @see ATNDeserializationOptions.isGenerateRuleBypassTransitions
*/
private static readonly bypassAltsAtnCache = new Map<string, ATN>();
/**
* The error handling strategy for the parser. The default value is a new
* instance of {@link DefaultErrorStrategy}.
*
* @see #getErrorHandler
* @see #setErrorHandler
*/
protected _errHandler: ANTLRErrorStrategy = new DefaultErrorStrategy();
/**
* The input stream.
*
* @see #getInputStream
* @see #setInputStream
*/
protected _input: TokenStream;
protected readonly _precedenceStack: IntegerStack = new IntegerStack();
/**
* The {@link ParserRuleContext} object for the currently executing rule.
*
* This is always non-undefined during the parsing process.
*/
protected _ctx: ParserRuleContext;
/**
* Specifies whether or not the parser should construct a parse tree during
* the parsing process. The default value is `true`.
*
* @see `buildParseTree`
*/
private _buildParseTrees: boolean = true;
/**
* When {@link #setTrace}`(true)` is called, a reference to the
* {@link TraceListener} is stored here so it can be easily removed in a
* later call to {@link #setTrace}`(false)`. The listener itself is
* implemented as a parser listener so this field is not directly used by
* other parser methods.
*/
private _tracer: TraceListener | undefined;
/**
* The list of {@link ParseTreeListener} listeners registered to receive
* events during the parse.
*
* @see #addParseListener
*/
protected _parseListeners: ParseTreeListener[] = [];
/**
* The number of syntax errors reported during parsing. This value is
* incremented each time {@link #notifyErrorListeners} is called.
*/
protected _syntaxErrors: number = 0;
/** Indicates parser has match()ed EOF token. See {@link #exitRule()}. */
protected matchedEOF: boolean = false;
constructor(input: TokenStream) {
super();
this._precedenceStack.push(0);
this.inputStream = input;
}
/** reset the parser's state */
public reset(): void;
public reset(resetInput: boolean): void;
public reset(resetInput?: boolean): void {
// Note: this method executes when not parsing, so _ctx can be undefined
if (resetInput === undefined || resetInput) {
this.inputStream.seek(0);
}
this._errHandler.reset(this);
this._ctx = undefined as any;
this._syntaxErrors = 0;
this.matchedEOF = false;
this.isTrace = false;
this._precedenceStack.clear();
this._precedenceStack.push(0);
let interpreter: ATNSimulator = this.interpreter;
if (interpreter != null) {
interpreter.reset();
}
}
/**
* Match current input symbol against `ttype`. If the symbol type
* matches, {@link ANTLRErrorStrategy#reportMatch} and {@link #consume} are
* called to complete the match process.
*
* If the symbol type does not match,
* {@link ANTLRErrorStrategy#recoverInline} is called on the current error
* strategy to attempt recovery. If {@link #getBuildParseTree} is
* `true` and the token index of the symbol returned by
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.
*
* @param ttype the token type to match
* @returns the matched symbol
* @ if the current input symbol did not match
* `ttype` and the error strategy could not recover from the
* mismatched symbol
*/
public match(ttype: number): Token {
let t: Token = this.currentToken;
if (t.type === ttype) {
if (ttype === Token.EOF) {
this.matchedEOF = true;
}
this._errHandler.reportMatch(this);
this.consume();
}
else {
t = this._errHandler.recoverInline(this);
if (this._buildParseTrees && t.tokenIndex === -1) {
// we must have conjured up a new token during single token insertion
// if it's not the current symbol
this._ctx.addErrorNode(this.createErrorNode(this._ctx, t));
}
}
return t;
}
/**
* Match current input symbol as a wildcard. If the symbol type matches
* (i.e. has a value greater than 0), {@link ANTLRErrorStrategy#reportMatch}
* and {@link #consume} are called to complete the match process.
*
* If the symbol type does not match,
* {@link ANTLRErrorStrategy#recoverInline} is called on the current error
* strategy to attempt recovery. If {@link #getBuildParseTree} is
* `true` and the token index of the symbol returned by
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
* the parse tree by calling {@link Parser#createErrorNode(ParserRuleContext, Token)} then
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.
*
* @returns the matched symbol
* @ if the current input symbol did not match
* a wildcard and the error strategy could not recover from the mismatched
* symbol
*/
public matchWildcard(): Token {
let t: Token = this.currentToken;
if (t.type > 0) {
this._errHandler.reportMatch(this);
this.consume();
}
else {
t = this._errHandler.recoverInline(this);
if (this._buildParseTrees && t.tokenIndex === -1) {
// we must have conjured up a new token during single token insertion
// if it's not the current symbol
this._ctx.addErrorNode(this.createErrorNode(this._ctx, t));
}
}
return t;
}
/**
* Track the {@link ParserRuleContext} objects during the parse and hook
* them up using the {@link ParserRuleContext#children} list so that it
* forms a parse tree. The {@link ParserRuleContext} returned from the start
* rule represents the root of the parse tree.
*
* 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.
*
* When we build parse trees, we are adding all of these contexts to
* {@link ParserRuleContext#children} list. Contexts are then not candidates
* for garbage collection.
*/
set buildParseTree(buildParseTrees: boolean) {
this._buildParseTrees = buildParseTrees;
}
/**
* Gets whether or not a complete parse tree will be constructed while
* parsing. This property is `true` for a newly constructed parser.
*
* @returns `true` if a complete parse tree will be constructed while
* parsing, otherwise `false`
*/
get buildParseTree(): boolean {
return this._buildParseTrees;
}
public getParseListeners(): ParseTreeListener[] {
return this._parseListeners;
}
/**
* Registers `listener` to receive events during the parsing process.
*
* 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
* {@link 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.
*
* With the following specific exceptions, calls to listener events are
* *deterministic*, i.e. for identical input the calls to listener
* methods will be the same.
*
* * Alterations to the grammar used to generate code may change the
* behavior of the listener calls.
* * Alterations to the command line options passed to ANTLR 4 when
* generating the parser may change the behavior of the listener calls.
* * Changing the version of the ANTLR Tool used to generate the parser
* may change the behavior of the listener calls.
*
* @param listener the listener to add
*
* @throws {@link TypeError} if `listener` is `undefined`
*/
public addParseListener( listener: ParseTreeListener): void {
if (listener == null) {
throw new TypeError("listener cannot be null");
}
this._parseListeners.push(listener);
}
/**
* Remove `listener` from the list of parse listeners.
*
* If `listener` is `undefined` or has not been added as a parse
* listener, this method does nothing.
*
* @see #addParseListener
*
* @param listener the listener to remove
*/
public removeParseListener(listener: ParseTreeListener): void {
let index = this._parseListeners.findIndex((l) => l === listener);
if (index !== -1) {
this._parseListeners.splice(index, 1);
}
}
/**
* Remove all parse listeners.
*
* @see #addParseListener
*/
public removeParseListeners(): void {
this._parseListeners.length = 0;
}
/**
* Notify any parse listeners of an enter rule event.
*
* @see #addParseListener
*/
protected triggerEnterRuleEvent(): void {
for (let listener of this._parseListeners) {
if (listener.enterEveryRule) {
listener.enterEveryRule(this._ctx);
}
this._ctx.enterRule(listener);
}
}
/**
* Notify any parse listeners of an exit rule event.
*
* @see #addParseListener
*/
protected triggerExitRuleEvent(): void {
// reverse order walk of listeners
for (let i = this._parseListeners.length - 1; i >= 0; i--) {
let listener: ParseTreeListener = this._parseListeners[i];
this._ctx.exitRule(listener);
if (listener.exitEveryRule) {
listener.exitEveryRule(this._ctx);
}
}
}
/**
* Gets the number of syntax errors reported during parsing. This value is
* incremented each time {@link #notifyErrorListeners} is called.
*
* @see #notifyErrorListeners
*/
get numberOfSyntaxErrors(): number {
return this._syntaxErrors;
}
get tokenFactory(): TokenFactory {
return this._input.tokenSource.tokenFactory;
}
/**
* The ATN with bypass alternatives is expensive to create so we create it
* lazily.
*
* @ if the current parser does not
* implement the `serializedATN` property.
*/
public getATNWithBypassAlts(): ATN {
let serializedAtn: string = this.serializedATN;
if (serializedAtn == null) {
throw new Error("The current parser does not support an ATN with bypass alternatives.");
}
let result = Parser.bypassAltsAtnCache.get(serializedAtn);
if (result == null) {
let deserializationOptions: ATNDeserializationOptions = new ATNDeserializationOptions();
deserializationOptions.isGenerateRuleBypassTransitions = true;
result = new ATNDeserializer(deserializationOptions).deserialize(Utils.toCharArray(serializedAtn));
Parser.bypassAltsAtnCache.set(serializedAtn, result);
}
return result;
}
/**
* The preferred method of getting a tree pattern. For example, here's a
* sample use:
*
* ```
* let t: ParseTree = parser.expr();
* let p: ParseTreePattern = await parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
* let m: ParseTreeMatch = p.match(t);
* let id: string = m.get("ID");
* ```
*/
public compileParseTreePattern(pattern: string, patternRuleIndex: number): Promise<ParseTreePattern>;
/**
* The same as {@link #compileParseTreePattern(String, int)} but specify a
* {@link Lexer} rather than trying to deduce it from this parser.
*/
public compileParseTreePattern(pattern: string, patternRuleIndex: number, lexer?: Lexer): Promise<ParseTreePattern>;
public async compileParseTreePattern(pattern: string, patternRuleIndex: number, lexer?: Lexer): Promise<ParseTreePattern> {
if (!lexer) {
if (this.inputStream) {
let tokenSource = this.inputStream.tokenSource;
if (tokenSource instanceof Lexer) {
lexer = tokenSource;
}
}
if (!lexer) {
throw new Error("Parser can't discover a lexer to use");
}
}
let currentLexer = lexer;
let m = await import("./tree/pattern/ParseTreePatternMatcher");
let matcher = new m.ParseTreePatternMatcher(currentLexer, this);
return matcher.compile(pattern, patternRuleIndex);
}
get errorHandler(): ANTLRErrorStrategy {
return this._errHandler;
}
set errorHandler( handler: ANTLRErrorStrategy) {
this._errHandler = handler;
}
get inputStream(): TokenStream {
return this._input;
}
/** Set the token stream and reset the parser. */
set inputStream(input: TokenStream) {
this.reset(false);
this._input = input;
}
/** Match needs to return the current input symbol, which gets put
* into the label for the associated token ref; e.g., x=ID.
*/
get currentToken(): Token {
return this._input.LT(1);
}
public notifyErrorListeners(/*@NotNull*/ msg: string): void;
public notifyErrorListeners(/*@NotNull*/ msg: string, /*@NotNull*/ offendingToken: Token | null, e: RecognitionException | undefined): void;
public notifyErrorListeners(msg: string, offendingToken?: Token | null, e?: RecognitionException | undefined): void {
if (offendingToken === undefined) {
offendingToken = this.currentToken;
} else if (offendingToken === null) {
offendingToken = undefined;
}
this._syntaxErrors++;
let line: number = -1;
let charPositionInLine: number = -1;
if (offendingToken != null) {
line = offendingToken.line;
charPositionInLine = offendingToken.charPositionInLine;
}
let listener = this.getErrorListenerDispatch();
if (listener.syntaxError) {
listener.syntaxError(this, offendingToken, line, charPositionInLine, msg, e);
}
}
/**
* Consume and return the [current symbol](`currentToken`).
*
* E.g., given the following input with `A` being the current
* lookahead symbol, this function moves the cursor to `B` and returns
* `A`.
*
* ```
* A B
* ^
* ```
*
* If the parser is not in error recovery mode, the consumed symbol is added
* to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and
* {@link ParseTreeListener#visitTerminal} is called on any parse listeners.
* If the parser *is* in error recovery mode, the consumed symbol is
* added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then
* {@link ParserRuleContext#addErrorNode(ErrorNode)} and
* {@link ParseTreeListener#visitErrorNode} is called on any parse
* listeners.
*/
public consume(): Token {
let o: Token = this.currentToken;
if (o.type !== Parser.EOF) {
this.inputStream.consume();
}
let hasListener: boolean = this._parseListeners.length !== 0;
if (this._buildParseTrees || hasListener) {
if (this._errHandler.inErrorRecoveryMode(this)) {
let node: ErrorNode = this._ctx.addErrorNode(this.createErrorNode(this._ctx, o));
if (hasListener) {
for (let listener of this._parseListeners) {
if (listener.visitErrorNode) {
listener.visitErrorNode(node);
}
}
}
}
else {
let node: TerminalNode = this.createTerminalNode(this._ctx, o);
this._ctx.addChild(node);
if (hasListener) {
for (let listener of this._parseListeners) {
if (listener.visitTerminal) {
listener.visitTerminal(node);
}
}
}
}
}
return o;
}
/**
* How to create a token leaf node associated with a parent.
* Typically, the terminal node to create is not a function of the parent.
*
* @since 4.7
*/
public createTerminalNode(parent: ParserRuleContext, t: Token): TerminalNode {
return new TerminalNode(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.
*
* @since 4.7
*/
public createErrorNode(parent: ParserRuleContext, t: Token): ErrorNode {
return new ErrorNode(t);
}
protected addContextToParseTree(): void {
let parent = this._ctx._parent as ParserRuleContext | undefined;
// add current context to parent if we have a parent
if (parent != null) {
parent.addChild(this._ctx);
}
}
/**
* Always called by generated parsers upon entry to a rule. Access field
* {@link #_ctx} get the current context.
*/
public enterRule( localctx: ParserRuleContext, state: number, ruleIndex: number): void {
this.state = state;
this._ctx = localctx;
this._ctx._start = this._input.LT(1);
if (this._buildParseTrees) {
this.addContextToParseTree();
}
this.triggerEnterRuleEvent();
}
public enterLeftFactoredRule(localctx: ParserRuleContext, state: number, ruleIndex: number): void {
this.state = state;
if (this._buildParseTrees) {
let factoredContext = this._ctx.getChild(this._ctx.childCount - 1) as ParserRuleContext;
this._ctx.removeLastChild();
factoredContext._parent = localctx;
localctx.addChild(factoredContext);
}
this._ctx = localctx;
this._ctx._start = this._input.LT(1);
if (this._buildParseTrees) {
this.addContextToParseTree();
}
this.triggerEnterRuleEvent();
}
public exitRule(): void {
if (this.matchedEOF) {
// if we have matched EOF, it cannot consume past EOF so we use LT(1) here
this._ctx._stop = this._input.LT(1); // LT(1) will be end of file
}
else {
this._ctx._stop = this._input.tryLT(-1); // stop node is what we just matched
}
// trigger event on _ctx, before it reverts to parent
this.triggerExitRuleEvent();
this.state = this._ctx.invokingState;
this._ctx = this._ctx._parent as ParserRuleContext;
}
public enterOuterAlt(localctx: ParserRuleContext, altNum: number): void {
localctx.altNumber = altNum;
// if we have new localctx, make sure we replace existing ctx
// that is previous child of parse tree
if (this._buildParseTrees && this._ctx !== localctx) {
let parent = this._ctx._parent as ParserRuleContext | undefined;
if (parent != null) {
parent.removeLastChild();
parent.addChild(localctx);
}
}
this._ctx = localctx;
}
/**
* Get the precedence level for the top-most precedence rule.
*
* @returns The precedence level for the top-most precedence rule, or -1 if
* the parser context is not nested within a precedence rule.
*/
get precedence(): number {
if (this._precedenceStack.isEmpty) {
return -1;
}
return this._precedenceStack.peek();
}
public enterRecursionRule(localctx: ParserRuleContext, state: number, ruleIndex: number, precedence: number): void {
this.state = state;
this._precedenceStack.push(precedence);
this._ctx = localctx;
this._ctx._start = this._input.LT(1);
this.triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
}
/** Like {@link #enterRule} but for recursive rules.
* Make the current context the child of the incoming localctx.
*/
public pushNewRecursionContext(localctx: ParserRuleContext, state: number, ruleIndex: number): void {
let previous: ParserRuleContext = this._ctx;
previous._parent = localctx;
previous.invokingState = state;
previous._stop = this._input.tryLT(-1);
this._ctx = localctx;
this._ctx._start = previous._start;
if (this._buildParseTrees) {
this._ctx.addChild(previous);
}
this.triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
}
public unrollRecursionContexts(_parentctx: ParserRuleContext): void {
this._precedenceStack.pop();
this._ctx._stop = this._input.tryLT(-1);
let retctx: ParserRuleContext = this._ctx; // save current ctx (return value)
// unroll so _ctx is as it was before call to recursive method
if (this._parseListeners.length > 0) {
while (this._ctx !== _parentctx) {
this.triggerExitRuleEvent();
this._ctx = this._ctx._parent as ParserRuleContext;
}
}
else {
this._ctx = _parentctx;
}
// hook into tree
retctx._parent = _parentctx;
if (this._buildParseTrees && _parentctx != null) {
// add return ctx into invoking rule's tree
_parentctx.addChild(retctx);
}
}
public getInvokingContext(ruleIndex: number): ParserRuleContext | undefined {
let p = this._ctx;
while (p && p.ruleIndex !== ruleIndex) {
p = p._parent as ParserRuleContext;
}
return p;
}
get context(): ParserRuleContext {
return this._ctx;
}
set context(ctx: ParserRuleContext) {
this._ctx = ctx;
}
public precpred( localctx: RuleContext, precedence: number): boolean {
return precedence >= this._precedenceStack.peek();
}
public getErrorListenerDispatch(): ParserErrorListener {
return new ProxyParserErrorListener(this.getErrorListeners());
}
public inContext(context: string): boolean {
// TODO: useful in parser?
return false;
}
/**
* Checks whether or not `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.
*
* ```
* return getExpectedTokens().contains(symbol);
* ```
*
* @param symbol the symbol type to check
* @returns `true` if `symbol` can follow the current state in
* the ATN, otherwise `false`.
*/
public isExpectedToken(symbol: number): boolean {
// return interpreter.atn.nextTokens(_ctx);
let atn: ATN = this.interpreter.atn;
let ctx: ParserRuleContext = this._ctx;
let s: ATNState = atn.states[this.state];
let following: IntervalSet = atn.nextTokens(s);
if (following.contains(symbol)) {
return true;
}
// System.out.println("following "+s+"="+following);
if (!following.contains(Token.EPSILON)) {
return false;
}
while (ctx != null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
let invokingState: ATNState = atn.states[ctx.invokingState];
let rt = invokingState.transition(0) as RuleTransition;
following = atn.nextTokens(rt.followState);
if (following.contains(symbol)) {
return true;
}
ctx = ctx._parent as ParserRuleContext;
}
if (following.contains(Token.EPSILON) && symbol === Token.EOF) {
return true;
}
return false;
}
get isMatchedEOF(): boolean {
return this.matchedEOF;
}
/**
* Computes the set of input symbols which could follow the current parser
* state and context, as given by {@link #getState} and {@link #getContext},
* respectively.
*
* @see ATN#getExpectedTokens(int, RuleContext)
*/
public getExpectedTokens(): IntervalSet {
return this.atn.getExpectedTokens(this.state, this.context);
}
public getExpectedTokensWithinCurrentRule(): IntervalSet {
let atn: ATN = this.interpreter.atn;
let s: ATNState = atn.states[this.state];
return atn.nextTokens(s);
}
/** Get a rule's index (i.e., `RULE_ruleName` field) or -1 if not found. */
public getRuleIndex(ruleName: string): number {
let ruleIndex = this.getRuleIndexMap().get(ruleName);
if (ruleIndex != null) {
return ruleIndex;
}
return -1;
}
get ruleContext(): ParserRuleContext { return this._ctx; }
/** Return List<String> 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.
*/
public getRuleInvocationStack(ctx: RuleContext = this._ctx): string[] {
let p: RuleContext | undefined = ctx; // Workaround for Microsoft/TypeScript#14487
let ruleNames: string[] = this.ruleNames;
let stack: string[] = [];
while (p != null) {
// compute what follows who invoked us
let ruleIndex: number = p.ruleIndex;
if (ruleIndex < 0) {
stack.push("n/a");
} else {
stack.push(ruleNames[ruleIndex]);
}
p = p._parent as RuleContext;
}
return stack;
}
/** For debugging and other purposes. */
public getDFAStrings(): string[] {
let s: string[] = [];
for (let dfa of this._interp.atn.decisionToDFA) {
s.push(dfa.toString(this.vocabulary, this.ruleNames));
}
return s;
}
/** For debugging and other purposes. */
public dumpDFA(): void {
let seenOne: boolean = false;
for (let dfa of this._interp.atn.decisionToDFA) {
if (!dfa.isEmpty) {
if (seenOne) {
console.log();
}
console.log("Decision " + dfa.decision + ":");
process.stdout.write(dfa.toString(this.vocabulary, this.ruleNames));
seenOne = true;
}
}
}
get sourceName(): string {
return this._input.sourceName;
}
get parseInfo(): Promise<ParseInfo | undefined> {
return import("./atn/ProfilingATNSimulator").then((m) => {
let interp: ParserATNSimulator = this.interpreter;
if (interp instanceof m.ProfilingATNSimulator) {
return new ParseInfo(interp);
}
return undefined;
});
}
/**
* @since 4.3
*/
public async setProfile(profile: boolean): Promise<void> {
let m = await import("./atn/ProfilingATNSimulator");
let interp: ParserATNSimulator = this.interpreter;
if (profile) {
if (!(interp instanceof m.ProfilingATNSimulator)) {
this.interpreter = new m.ProfilingATNSimulator(this);
}
} else if (interp instanceof m.ProfilingATNSimulator) {
this.interpreter = new ParserATNSimulator(this.atn, this);
}
this.interpreter.setPredictionMode(interp.getPredictionMode());
}
/** 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.
*/
set isTrace(trace: boolean) {
if (!trace) {
if (this._tracer) {
this.removeParseListener(this._tracer);
this._tracer = undefined;
}
}
else {
if (this._tracer) {
this.removeParseListener(this._tracer);
} else {
this._tracer = new TraceListener(this.ruleNames, this._input);
}
this.addParseListener(this._tracer);
}
}
/**
* Gets whether a {@link TraceListener} is registered as a parse listener
* for the parser.
*/
get isTrace(): boolean {
return this._tracer != null;
}
}