@@ -4,7 +4,14 @@ import {
44 ANTLRErrorListener ,
55 RecognitionException ,
66 ATNSimulator ,
7+ LexerNoViableAltException ,
8+ Lexer ,
9+ Parser ,
10+ InputMismatchException ,
11+ NoViableAltException ,
712} from 'antlr4ng' ;
13+ import { LOCALE_TYPE } from './types' ;
14+ import { transform } from './transform' ;
815
916/**
1017 * Converted from {@link SyntaxError}.
@@ -39,10 +46,12 @@ export interface SyntaxError {
3946 */
4047export type ErrorListener = ( parseError : ParseError , originalError : SyntaxError ) => void ;
4148
42- export class ParseErrorListener implements ANTLRErrorListener {
49+ export abstract class ParseErrorListener implements ANTLRErrorListener {
4350 private _errorListener : ErrorListener ;
51+ private locale : LOCALE_TYPE ;
4452
45- constructor ( errorListener : ErrorListener ) {
53+ constructor ( errorListener : ErrorListener , locale : LOCALE_TYPE = 'en_US' ) {
54+ this . locale = locale ;
4655 this . _errorListener = errorListener ;
4756 }
4857
@@ -52,6 +61,8 @@ export class ParseErrorListener implements ANTLRErrorListener {
5261
5362 reportContextSensitivity ( ) { }
5463
64+ protected abstract getExpectedText ( parser : Parser , token : Token ) : string ;
65+
5566 syntaxError (
5667 recognizer : Recognizer < ATNSimulator > ,
5768 offendingSymbol : Token | null ,
@@ -60,6 +71,87 @@ export class ParseErrorListener implements ANTLRErrorListener {
6071 msg : string ,
6172 e : RecognitionException
6273 ) {
74+ let message = '' ;
75+ // If not undefined then offendingSymbol is of type Token.
76+ if ( offendingSymbol ) {
77+ let token = offendingSymbol as Token ;
78+ const parser = recognizer as Parser ;
79+
80+ // judge token is EOF
81+ const isEof = token . type === Token . EOF ;
82+ if ( isEof ) {
83+ token = parser . tokenStream . get ( token . tokenIndex - 1 ) ;
84+ }
85+ const wrongText = token . text ?? '' ;
86+
87+ const isInComplete = isEof && wrongText !== ' ' ;
88+
89+ const expectedText = isInComplete ? '' : this . getExpectedText ( parser , token ) ;
90+
91+ if ( ! e ) {
92+ // handle missing or unwanted tokens.
93+ message = msg ;
94+ if ( msg . includes ( 'extraneous' ) ) {
95+ message = `'${ wrongText } ' {noValidPosition}${
96+ expectedText . length ? `{expecting}${ expectedText } ` : ''
97+ } `;
98+ }
99+ if ( msg . includes ( 'missing' ) ) {
100+ const regex = / m i s s i n g \s + ' ( [ ^ ' ] + ) ' / ;
101+ const match = msg . match ( regex ) ;
102+ message = `{missing}` ;
103+ if ( match ) {
104+ const missKeyword = match [ 1 ] ;
105+ message += `'${ missKeyword } '` ;
106+ } else {
107+ message += `{keyword}` ;
108+ }
109+ message += `{at}'${ wrongText } '` ;
110+ }
111+ } else {
112+ // handle mismatch exception or no viable alt exception
113+ if ( e instanceof InputMismatchException || e instanceof NoViableAltException ) {
114+ if ( isEof ) {
115+ message = `{stmtInComplete}` ;
116+ } else {
117+ message = `'${ wrongText } ' {noValidPosition}` ;
118+ }
119+ if ( expectedText . length > 0 ) {
120+ message += `{expecting}${ expectedText } ` ;
121+ }
122+ } else {
123+ message = msg ;
124+ }
125+ }
126+ } else {
127+ // No offending symbol, which indicates this is a lexer error.
128+ if ( e instanceof LexerNoViableAltException ) {
129+ const lexer = recognizer as Lexer ;
130+ const input = lexer . inputStream ;
131+ let text = lexer . getErrorDisplay (
132+ input . getText ( lexer . _tokenStartCharIndex , input . index )
133+ ) ;
134+ switch ( text [ 0 ] ) {
135+ case '/' :
136+ message = '{unfinishedMultilineComment}' ;
137+ break ;
138+ case '"' :
139+ message = '{unfinishedDoubleQuoted}' ;
140+ break ;
141+ case "'" :
142+ message = '{unfinishedSingleQuoted}' ;
143+ break ;
144+ case '`' :
145+ message = '{unfinishedTickQuoted}' ;
146+ break ;
147+
148+ default :
149+ message = '"' + text + '" {noValidInput}' ;
150+ break ;
151+ }
152+ }
153+ }
154+ message = transform ( message , this . locale ) ;
63155 let endCol = charPositionInLine + 1 ;
64156 if ( offendingSymbol && offendingSymbol . text !== null ) {
65157 endCol = charPositionInLine + offendingSymbol . text . length ;
@@ -71,7 +163,7 @@ export class ParseErrorListener implements ANTLRErrorListener {
71163 endLine : line ,
72164 startColumn : charPositionInLine + 1 ,
73165 endColumn : endCol + 1 ,
74- message : msg ,
166+ message,
75167 } ,
76168 {
77169 e,
0 commit comments