2023-05-30 14:44:03 +08:00
|
|
|
import { Parser } from 'antlr4ts';
|
|
|
|
import { ParseTreeWalker } from 'antlr4ts/tree';
|
|
|
|
|
2020-09-11 17:39:10 +08:00
|
|
|
import ParserErrorListener, {
|
|
|
|
ParserError,
|
|
|
|
ErrorHandler,
|
|
|
|
ParserErrorCollector,
|
|
|
|
} from './parserErrorListener';
|
|
|
|
|
2023-05-30 14:44:03 +08:00
|
|
|
interface IParser extends Parser {
|
2023-05-04 10:13:05 +08:00
|
|
|
// Lost in type definition
|
|
|
|
ruleNames: string[];
|
|
|
|
// Customized in our parser
|
|
|
|
program(): any;
|
|
|
|
}
|
|
|
|
|
2020-09-11 17:39:10 +08:00
|
|
|
/**
|
|
|
|
* Custom Parser class, subclass needs extends it.
|
|
|
|
*/
|
2023-05-04 10:13:05 +08:00
|
|
|
export default abstract class BasicParser {
|
2023-05-30 14:44:03 +08:00
|
|
|
private _parser: IParser;
|
2020-09-11 17:39:10 +08:00
|
|
|
|
|
|
|
public parse(
|
|
|
|
input: string,
|
2023-05-04 10:13:05 +08:00
|
|
|
errorListener?: ErrorHandler<any>,
|
2020-09-11 17:39:10 +08:00
|
|
|
) {
|
|
|
|
const parser = this.createParser(input);
|
|
|
|
this._parser = parser;
|
|
|
|
|
|
|
|
parser.removeErrorListeners();
|
|
|
|
parser.addErrorListener(new ParserErrorListener(errorListener));
|
|
|
|
|
2022-12-16 02:58:20 +08:00
|
|
|
const parserTree = parser.program();
|
2020-09-11 17:39:10 +08:00
|
|
|
|
|
|
|
return parserTree;
|
|
|
|
}
|
|
|
|
|
|
|
|
public validate(input: string): ParserError[] {
|
|
|
|
const lexerError = []; const syntaxErrors = [];
|
|
|
|
|
|
|
|
const parser = this.createParser(input);
|
|
|
|
this._parser = parser;
|
|
|
|
|
|
|
|
parser.removeErrorListeners();
|
|
|
|
parser.addErrorListener(new ParserErrorCollector(syntaxErrors));
|
|
|
|
|
2022-12-16 02:58:20 +08:00
|
|
|
parser.program();
|
2020-09-11 17:39:10 +08:00
|
|
|
return lexerError.concat(syntaxErrors);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create antrl4 Lexer object
|
|
|
|
* @param input source string
|
|
|
|
*/
|
2023-05-04 10:13:05 +08:00
|
|
|
public abstract createLexer(input: string);
|
2020-09-11 17:39:10 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create Parser by lexer
|
|
|
|
* @param lexer Lexer
|
|
|
|
*/
|
2023-05-04 10:13:05 +08:00
|
|
|
public abstract createParserFromLexer(lexer);
|
2020-09-11 17:39:10 +08:00
|
|
|
|
|
|
|
/**
|
2023-05-04 10:13:05 +08:00
|
|
|
* Get all Tokens of input string
|
2020-09-11 17:39:10 +08:00
|
|
|
* @param input string
|
2023-05-04 10:13:05 +08:00
|
|
|
* @returns Token[]
|
2020-09-11 17:39:10 +08:00
|
|
|
*/
|
2023-05-04 10:13:05 +08:00
|
|
|
public getAllTokens(input: string): string[] {
|
|
|
|
const lexer = this.createLexer(input);
|
2023-05-30 14:44:03 +08:00
|
|
|
return lexer.getAllTokens().map(token => token.text);
|
2020-09-11 17:39:10 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get Parser instance by input string
|
|
|
|
* @param input
|
|
|
|
*/
|
2023-05-30 14:44:03 +08:00
|
|
|
public createParser(input: string): IParser {
|
2020-09-11 17:39:10 +08:00
|
|
|
const lexer = this.createLexer(input);
|
|
|
|
const parser: any = this.createParserFromLexer(lexer);
|
|
|
|
parser.buildParseTrees = true;
|
|
|
|
this._parser = parser;
|
|
|
|
|
|
|
|
return parser;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* It convert tree to string, it's convenient to use in unit test.
|
|
|
|
* @param string input
|
|
|
|
*/
|
|
|
|
public parserTreeToString(input: string): string {
|
|
|
|
const parser = this.createParser(input);
|
|
|
|
this._parser = parser;
|
|
|
|
|
2022-12-16 02:58:20 +08:00
|
|
|
const tree = parser.program();
|
2020-09-11 17:39:10 +08:00
|
|
|
return tree.toStringTree(parser.ruleNames);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get List-like style tree string
|
|
|
|
* @param parserTree
|
|
|
|
*/
|
|
|
|
public toString(parserTree: any): string {
|
|
|
|
return parserTree.toStringTree(this._parser.ruleNames);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param listener Listener instance extends ParserListener
|
|
|
|
* @param parserTree parser Tree
|
|
|
|
*/
|
|
|
|
public listen(listener: any, parserTree: any) {
|
|
|
|
ParseTreeWalker.DEFAULT.walk(listener, parserTree);
|
|
|
|
}
|
|
|
|
}
|