Refactor/basic parser (#182)

* feat: replace errorCollector with ParserErrorListener to collect lexer error

* refactor: remove useless method in basicParser

* feat: correct splitSQLByStatement method

* feat: rename parse to parseWithCache and add new parse method

* refactor: rename parserTree to parseTree

* test: rename parserTree to parseTree

* refactor: rename parserError to parseError

* feat: export ErrorHandler type

* feat: use errorhandler form params

* test: basic parser unit tests

* style: lint via prettier
This commit is contained in:
Hayden 2023-10-16 17:59:28 +08:00 committed by GitHub
parent 2f1325d4fc
commit f9dbd9fc23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 321 additions and 207 deletions

View File

@ -1,3 +1,4 @@
module.exports = { module.exports = {
'*.js|ts': [`prettier --write`], '*.js': [`prettier --write`],
'*.ts': [`prettier --write`],
}; };

View File

@ -17,4 +17,4 @@ export * from './lib/trinosql/TrinoSqlVisitor';
export { SyntaxContextType } from './parser/common/basic-parser-types'; export { SyntaxContextType } from './parser/common/basic-parser-types';
export type * from './parser/common/basic-parser-types'; export type * from './parser/common/basic-parser-types';
export type { SyntaxError, ParserError } from './parser/common/parserErrorListener'; export type { SyntaxError, ParseError, ErrorHandler } from './parser/common/parseErrorListener';

View File

@ -71,10 +71,13 @@ export interface Suggestions<T = WordRange> {
} }
export interface TextSlice { export interface TextSlice {
/** start at 0 */
startIndex: number; startIndex: number;
endIndex: number; endIndex: number;
/** start at 1 */
startLine: number; startLine: number;
endLine: number; endLine: number;
/** start at 1 */
startColumn: number; startColumn: number;
endColumn: number; endColumn: number;
text: string; text: string;

View File

@ -17,11 +17,7 @@ import {
WordRange, WordRange,
TextSlice, TextSlice,
} from './basic-parser-types'; } from './basic-parser-types';
import ParserErrorListener, { import ParseErrorListener, { ParseError, ErrorHandler } from './parseErrorListener';
ParserError,
ErrorHandler,
ParserErrorCollector,
} from './parserErrorListener';
interface IParser<IParserRuleContext extends ParserRuleContext> extends Parser { interface IParser<IParserRuleContext extends ParserRuleContext> extends Parser {
// Customized in our parser // Customized in our parser
@ -40,13 +36,19 @@ export default abstract class BasicParser<
PRC extends ParserRuleContext = ParserRuleContext, PRC extends ParserRuleContext = ParserRuleContext,
P extends IParser<PRC> = IParser<PRC>, P extends IParser<PRC> = IParser<PRC>,
> { > {
/** members for cache start */
protected _charStreams: CodePointCharStream; protected _charStreams: CodePointCharStream;
protected _lexer: L; protected _lexer: L;
protected _tokenStream: CommonTokenStream; protected _tokenStream: CommonTokenStream;
protected _parser: P; protected _parser: P;
protected _parserTree: PRC; protected _parseTree: PRC;
protected _errorCollector: ParserErrorCollector = new ParserErrorCollector();
protected _parsedInput: string = null; protected _parsedInput: string = null;
protected _parseErrors: ParseError[] = [];
/** members for cache end */
private _errorHandler: ErrorHandler<any> = (error) => {
this._parseErrors.push(error);
};
/** /**
* PreferredRules for antlr4-c3 * PreferredRules for antlr4-c3
@ -54,7 +56,7 @@ export default abstract class BasicParser<
protected abstract preferredRules: Set<number>; protected abstract preferredRules: Set<number>;
/** /**
* Create a antrl4 Lexer instance * Create a antlr4 Lexer instance.
* @param input source string * @param input source string
*/ */
protected abstract createLexerFormCharStream(charStreams: CodePointCharStream): L; protected abstract createLexerFormCharStream(charStreams: CodePointCharStream): L;
@ -70,8 +72,7 @@ export default abstract class BasicParser<
* @param candidates candidate list * @param candidates candidate list
* @param allTokens all tokens from input * @param allTokens all tokens from input
* @param caretTokenIndex tokenIndex of caretPosition * @param caretTokenIndex tokenIndex of caretPosition
* @param tokenIndexOffset offset of the tokenIndex in the candidates * @param tokenIndexOffset offset of the tokenIndex in the candidates compared to the tokenIndex in allTokens
* compared to the tokenIndex in allTokens
*/ */
protected abstract processCandidates( protected abstract processCandidates(
candidates: CandidatesCollection, candidates: CandidatesCollection,
@ -86,38 +87,68 @@ export default abstract class BasicParser<
protected abstract get splitListener(): SplitListener; protected abstract get splitListener(): SplitListener;
/** /**
* Create an anltr4 lexer from input. * Create an antlr4 lexer from input.
* @param input string * @param input string
*/ */
public createLexer(input: string) { public createLexer(input: string, errorListener?: ErrorHandler<any>) {
const charStreams = CharStreams.fromString(input.toUpperCase()); const charStreams = CharStreams.fromString(input.toUpperCase());
const lexer = this.createLexerFormCharStream(charStreams); const lexer = this.createLexerFormCharStream(charStreams);
if (errorListener) {
lexer.removeErrorListeners();
lexer.addErrorListener(new ParseErrorListener(errorListener));
}
return lexer; return lexer;
} }
/** /**
* Create an anltr4 parser from input. * Create an antlr4 parser from input.
* @param input string * @param input string
*/ */
public createParser(input: string) { public createParser(input: string, errorListener?: ErrorHandler<any>) {
const lexer = this.createLexer(input); const lexer = this.createLexer(input, errorListener);
const tokenStream = new CommonTokenStream(lexer); const tokenStream = new CommonTokenStream(lexer);
const parser = this.createParserFromTokenStream(tokenStream); const parser = this.createParserFromTokenStream(tokenStream);
if (errorListener) {
parser.removeErrorListeners();
parser.addErrorListener(new ParseErrorListener(errorListener));
}
return parser; return parser;
} }
/** /**
* Create an anltr4 parser from input. * Parse input string and return parseTree.
* @param input string
* @param errorListener listen parse errors and lexer errors.
* @returns parseTree
*/
public parse(input: string, errorListener?: ErrorHandler<any>) {
const parser = this.createParser(input, errorListener);
parser.buildParseTree = true;
return parser.program();
}
/**
* Create an antlr4 parser from input.
* And the instances will be cache. * And the instances will be cache.
* @param input string * @param input string
*/ */
protected createParserWithCache(input: string): P { private createParserWithCache(input: string): P {
this._parserTree = null; this._parseTree = null;
this._charStreams = CharStreams.fromString(input.toUpperCase()); this._charStreams = CharStreams.fromString(input.toUpperCase());
this._lexer = this.createLexerFormCharStream(this._charStreams); this._lexer = this.createLexerFormCharStream(this._charStreams);
this._lexer.removeErrorListeners();
this._lexer.addErrorListener(new ParseErrorListener(this._errorHandler));
this._tokenStream = new CommonTokenStream(this._lexer); this._tokenStream = new CommonTokenStream(this._lexer);
/**
* All tokens are generated in advance.
* This can cause performance degradation, but it seems necessary for now.
* Because the tokens will be used multiple times.
*/
this._tokenStream.fill(); this._tokenStream.fill();
this._parser = this.createParserFromTokenStream(this._tokenStream); this._parser = this.createParserFromTokenStream(this._tokenStream);
@ -132,28 +163,23 @@ export default abstract class BasicParser<
* unless the errorListener parameter is passed. * unless the errorListener parameter is passed.
* @param input source string * @param input source string
* @param errorListener listen errors * @param errorListener listen errors
* @returns parserTree * @returns parseTree
*/ */
public parse(input: string, errorListener?: ErrorHandler<any>) { private parseWithCache(input: string, errorListener?: ErrorHandler<any>) {
// Avoid parsing the same input repeatedly. // Avoid parsing the same input repeatedly.
if (this._parsedInput === input && !errorListener) { if (this._parsedInput === input && !errorListener) {
return this._parserTree; return this._parseTree;
} }
this._parseErrors = [];
const parser = this.createParserWithCache(input); const parser = this.createParserWithCache(input);
this._parsedInput = input; this._parsedInput = input;
parser.removeErrorListeners(); parser.removeErrorListeners();
this._errorCollector.clear(); parser.addErrorListener(new ParseErrorListener(this._errorHandler));
parser.addErrorListener(this._errorCollector); this._parseTree = parser.program();
if (errorListener) {
parser.addErrorListener(new ParserErrorListener(errorListener));
}
this._parserTree = parser.program(); return this._parseTree;
return this._parserTree;
} }
/** /**
@ -161,51 +187,34 @@ export default abstract class BasicParser<
* @param input source string * @param input source string
* @returns syntax errors * @returns syntax errors
*/ */
public validate(input: string): ParserError[] { public validate(input: string): ParseError[] {
this.parse(input); this.parseWithCache(input);
const lexerError = []; return this._parseErrors;
return lexerError.concat(this._errorCollector.parserErrors);
} }
/** /**
* Get all Tokens of input string'<EOF>' is not included * Get all Tokens of input string'<EOF>' is not included.
* @param input source string * @param input source string
* @returns Token[] * @returns Token[]
*/ */
public getAllTokens(input: string): Token[] { public getAllTokens(input: string): Token[] {
this.parse(input); this.parseWithCache(input);
let allTokens = this._tokenStream.getTokens(); let allTokens = this._tokenStream.getTokens();
if (allTokens[allTokens.length - 1].text === '<EOF>') { if (allTokens[allTokens.length - 1].text === '<EOF>') {
allTokens = allTokens.slice(0, -1); allTokens = allTokens.slice(0, -1);
} }
return allTokens; return allTokens;
} }
/**
* It convert tree to string, it's convenient to use in unit test.
* @param string input
*/
public parserTreeToString(input: string): string {
this.parse(input);
return this._parserTree.toStringTree(this._parser.ruleNames);
}
/**
* Get List-like style tree string
* @param parserTree ProgramRuleContext
*/
public toString(parserTree: PRC): string {
return parserTree.toStringTree(this._parser.ruleNames);
}
/** /**
* @param listener Listener instance extends ParserListener * @param listener Listener instance extends ParserListener
* @param parserTree parser Tree * @param parseTree parser Tree
*/ */
public listen<PTL extends ParseTreeListener = ParseTreeListener>( public listen<PTL extends ParseTreeListener = ParseTreeListener>(
listener: PTL, listener: PTL,
parserTree: PRC parseTree: PRC
) { ) {
ParseTreeWalker.DEFAULT.walk(listener, parserTree); ParseTreeWalker.DEFAULT.walk(listener, parseTree);
} }
/** /**
@ -214,9 +223,15 @@ export default abstract class BasicParser<
* @param input source string * @param input source string
*/ */
public splitSQLByStatement(input): TextSlice[] { public splitSQLByStatement(input): TextSlice[] {
this.parse(input); const errors = this.validate(input);
if (errors.length) {
return null;
}
const splitListener = this.splitListener; const splitListener = this.splitListener;
this.listen(splitListener, this._parserTree); // TODO: add splitListener to all sqlParser implements add remove following if
if (!splitListener) return null;
this.listen(splitListener, this._parseTree);
const res = splitListener.statementsContext.map((context) => { const res = splitListener.statementsContext.map((context) => {
const { start, stop } = context; const { start, stop } = context;
@ -248,11 +263,11 @@ export default abstract class BasicParser<
// TODO: add splitListener to all sqlParser implements add remove following if // TODO: add splitListener to all sqlParser implements add remove following if
if (!splitListener) return null; if (!splitListener) return null;
this.parse(input); this.parseWithCache(input);
let sqlParserIns = this._parser; let sqlParserIns = this._parser;
const allTokens = this.getAllTokens(input); const allTokens = this.getAllTokens(input);
let caretTokenIndex = findCaretTokenIndex(caretPosition, allTokens); let caretTokenIndex = findCaretTokenIndex(caretPosition, allTokens);
let c3Context: ParserRuleContext = this._parserTree; let c3Context: ParserRuleContext = this._parseTree;
let tokenIndexOffset: number = 0; let tokenIndexOffset: number = 0;
if (!caretTokenIndex && caretTokenIndex !== 0) return null; if (!caretTokenIndex && caretTokenIndex !== 0) return null;
@ -261,7 +276,7 @@ export default abstract class BasicParser<
* Split sql by statement. * Split sql by statement.
* Try to collect candidates from the caret statement only. * Try to collect candidates from the caret statement only.
*/ */
this.listen(splitListener, this._parserTree); this.listen(splitListener, this._parseTree);
// If there are multiple statements. // If there are multiple statements.
if (splitListener.statementsContext.length > 1) { if (splitListener.statementsContext.length > 1) {
@ -282,7 +297,7 @@ export default abstract class BasicParser<
/** /**
* If caretStatementContext is not found and it follows all statements. * If caretStatementContext is not found and it follows all statements.
* Reparses part of the input following the penultimate statement. * Reparses part of the input following the penultimate statement.
* And c3 will collect candidates in the new parserTreeContext. * And c3 will collect candidates in the new parseTreeContext.
*/ */
if (caretTokenIndex > lastStatementToken?.tokenIndex) { if (caretTokenIndex > lastStatementToken?.tokenIndex) {
/** /**
@ -295,11 +310,14 @@ export default abstract class BasicParser<
const inputSlice = input.slice(lastStatementToken.startIndex); const inputSlice = input.slice(lastStatementToken.startIndex);
const lexer = this.createLexer(inputSlice); const lexer = this.createLexer(inputSlice);
lexer.removeErrorListeners();
const tokenStream = new CommonTokenStream(lexer); const tokenStream = new CommonTokenStream(lexer);
tokenStream.fill(); tokenStream.fill();
const parser = this.createParserFromTokenStream(tokenStream); const parser = this.createParserFromTokenStream(tokenStream);
parser.removeErrorListeners(); parser.removeErrorListeners();
parser.buildParseTree = true; parser.buildParseTree = true;
sqlParserIns = parser; sqlParserIns = parser;
c3Context = parser.program(); c3Context = parser.program();
} }

View File

@ -0,0 +1,72 @@
import { Token, Recognizer, ANTLRErrorListener, RecognitionException } from 'antlr4ts';
import { ATNSimulator } from 'antlr4ts/atn/ATNSimulator';
/**
* Converted from {@link SyntaxError}.
*/
export interface ParseError {
startLine: number;
endLine: number;
startCol: number;
endCol: number;
message: string;
}
/**
* The type of error resulting from lexical parsing and parsing.
*/
export interface SyntaxError<T> {
recognizer: Recognizer<T, ATNSimulator>;
offendingSymbol: Token;
line: number;
charPositionInLine: number;
msg: string;
e: RecognitionException;
}
/**
* ErrorHandler will be invoked when it encounters a parsing error.
* Includes lexical errors and parsing errors.
*/
export type ErrorHandler<T> = (parseError: ParseError, originalError: SyntaxError<T>) => void;
export default class ParseErrorListener implements ANTLRErrorListener<Token> {
private _errorHandler;
constructor(errorListener: ErrorHandler<Token>) {
this._errorHandler = errorListener;
}
syntaxError(
recognizer: Recognizer<Token, ATNSimulator>,
offendingSymbol,
line: number,
charPositionInLine: number,
msg: string,
e: RecognitionException
) {
let endCol = charPositionInLine + 1;
if (offendingSymbol && offendingSymbol.text !== null) {
endCol = charPositionInLine + offendingSymbol.text.length;
}
if (this._errorHandler) {
this._errorHandler(
{
startLine: line,
endLine: line,
startCol: charPositionInLine,
endCol: endCol,
message: msg,
},
{
e,
line,
msg,
recognizer,
offendingSymbol,
charPositionInLine,
}
);
}
}
}

View File

@ -1,106 +0,0 @@
import { Token, Recognizer, ParserErrorListener, RecognitionException } from 'antlr4ts';
import { ATNSimulator } from 'antlr4ts/atn/ATNSimulator';
export interface ParserError {
startLine: number;
endLine: number;
startCol: number;
endCol: number;
message: string;
}
export interface SyntaxError<T> {
recognizer: Recognizer<T, ATNSimulator>;
offendingSymbol: Token;
line: number;
charPositionInLine: number;
msg: string;
e: RecognitionException;
}
export type ErrorHandler<T> = (err: ParserError, errOption: SyntaxError<T>) => void;
export class ParserErrorCollector implements ParserErrorListener {
private _parseErrors: ParserError[] = [];
private _syntaxErrors: SyntaxError<Token>[] = [];
syntaxError(
recognizer: Recognizer<Token, ATNSimulator>,
offendingSymbol: Token,
line: number,
charPositionInLine: number,
msg: string,
e: RecognitionException
) {
let endCol = charPositionInLine + 1;
if (offendingSymbol && offendingSymbol.text !== null) {
endCol = charPositionInLine + (offendingSymbol.text?.length ?? 0);
}
this._parseErrors.push({
startLine: line,
endLine: line,
startCol: charPositionInLine,
endCol: endCol,
message: msg,
});
this._syntaxErrors.push({
e,
line,
msg,
recognizer,
offendingSymbol,
charPositionInLine,
});
}
clear() {
this._parseErrors = [];
this._syntaxErrors = [];
}
get parserErrors() {
return this._parseErrors;
}
}
export default class CustomParserErrorListener implements ParserErrorListener {
private _errorHandler;
constructor(errorListener: ErrorHandler<Token>) {
this._errorHandler = errorListener;
}
syntaxError(
recognizer: Recognizer<Token, ATNSimulator>,
offendingSymbol: Token,
line: number,
charPositionInLine: number,
msg: string,
e: RecognitionException
) {
let endCol = charPositionInLine + 1;
if (offendingSymbol && offendingSymbol.text !== null) {
endCol = charPositionInLine + offendingSymbol.text.length;
}
if (this._errorHandler) {
this._errorHandler(
{
startLine: line,
endLine: line,
startCol: charPositionInLine,
endCol: endCol,
message: msg,
},
{
e,
line,
msg,
recognizer,
offendingSymbol,
charPositionInLine,
}
);
}
}
}

View File

@ -1,13 +1,7 @@
import { Token } from 'antlr4ts'; import { Token } from 'antlr4ts';
import { CandidatesCollection } from 'antlr4-c3'; import { CandidatesCollection } from 'antlr4-c3';
import { HiveSqlLexer } from '../lib/hive/HiveSqlLexer'; import { HiveSqlLexer } from '../lib/hive/HiveSqlLexer';
import { import { HiveSqlParser, ProgramContext, StatementContext } from '../lib/hive/HiveSqlParser';
HiveSqlParser,
ProgramContext,
StatementContext,
ExplainStatementContext,
ExecStatementContext,
} from '../lib/hive/HiveSqlParser';
import BasicParser from './common/basicParser'; import BasicParser from './common/basicParser';
import { HiveSqlParserListener } from '../lib/hive/HiveSqlParserListener'; import { HiveSqlParserListener } from '../lib/hive/HiveSqlParserListener';
import { SyntaxContextType, Suggestions, SyntaxSuggestion } from './common/basic-parser-types'; import { SyntaxContextType, Suggestions, SyntaxSuggestion } from './common/basic-parser-types';

View File

@ -0,0 +1,132 @@
import { CommonTokenStream } from 'antlr4ts';
import { ErrorHandler, FlinkSQL } from '../../src';
import { FlinkSqlLexer } from '../../src/lib/flinksql/FlinkSqlLexer';
describe('BasicParser unit tests', () => {
const flinkParser = new FlinkSQL();
test('Create lexer', () => {
const sql = 'SELECT * FROM tb1';
const lexer = flinkParser.createLexer(sql);
expect(lexer).not.toBeUndefined();
expect(lexer).not.toBeNull();
});
test('Create lexer with errorHandler', () => {
const sql = '袋鼠云数栈UED团队';
const errors: any[] = [];
const errorHandler: ErrorHandler<any> = (err) => {
errors.push(err);
};
const lexer = flinkParser.createLexer(sql, errorHandler);
const tokenStream = new CommonTokenStream(lexer);
tokenStream.fill();
expect(errors.length).not.toBe(0);
});
test('Create parser', () => {
const sql = 'SELECT * FROM tb1';
const parser = flinkParser.createParser(sql);
expect(parser).not.toBeUndefined();
expect(parser).not.toBeNull();
});
test('Create parser with errorHandler (lexer error)', () => {
const sql = '袋鼠云数栈UED团队';
const errors: any[] = [];
const errorHandler: ErrorHandler<any> = (err) => {
errors.push(err);
};
const parser = flinkParser.createParser(sql, errorHandler);
parser.program();
expect(errors.length).not.toBe(0);
});
test('Create parser with errorHandler (parse error)', () => {
const sql = 'SHOW TA';
const errors: any[] = [];
const errorHandler: ErrorHandler<any> = (err) => {
errors.push(err);
};
const parser = flinkParser.createParser(sql, errorHandler);
parser.program();
expect(errors.length).not.toBe(0);
});
test('Parse right input', () => {
const sql = 'SELECT * FROM tb1';
const errors: any[] = [];
const errorHandler: ErrorHandler<any> = (err) => {
errors.push(err);
};
const parseTree = flinkParser.parse(sql, errorHandler);
expect(parseTree).not.toBeUndefined();
expect(parseTree).not.toBeNull();
expect(errors.length).toBe(0);
});
test('Parse wrong input', () => {
const sql = '袋鼠云数栈UED团队';
const errors: any[] = [];
const errorHandler: ErrorHandler<any> = (err) => {
errors.push(err);
};
const parseTree = flinkParser.parse(sql, errorHandler);
expect(parseTree).not.toBeUndefined();
expect(parseTree).not.toBeNull();
expect(errors.length).not.toBe(0);
});
test('Get All tokens', () => {
const sql = 'SELECT * FROM tbl1;';
const tokens = flinkParser.getAllTokens(sql);
expect(tokens.length).toBe(8);
expect(tokens[0].type).toBe(FlinkSqlLexer.KW_SELECT);
expect(tokens[1].type).toBe(FlinkSqlLexer.SPACE);
expect(tokens[2].type).toBe(FlinkSqlLexer.ASTERISK_SIGN);
expect(tokens[3].type).toBe(FlinkSqlLexer.SPACE);
expect(tokens[4].type).toBe(FlinkSqlLexer.KW_FROM);
expect(tokens[5].type).toBe(FlinkSqlLexer.SPACE);
expect(tokens[6].type).toBe(FlinkSqlLexer.ID_LITERAL);
expect(tokens[7].type).toBe(FlinkSqlLexer.SEMICOLON);
});
test('Get All tokens with error', () => {
const sql = '袋鼠云数栈UED团队';
const tokens = flinkParser.getAllTokens(sql);
expect(tokens.length).toBe(1);
expect(tokens[0].type).toBe(FlinkSqlLexer.ID_LITERAL);
});
test('Split sql', () => {
const sql = 'SHOW TABLES;\nSELECT * FROM tb;';
const sqlSlices = flinkParser.splitSQLByStatement(sql);
expect(sqlSlices.length).toBe(2);
expect(sqlSlices[0].text).toBe('SHOW TABLES;');
expect(sql.slice(sqlSlices[0].startIndex, sqlSlices[0].endIndex + 1)).toBe(
sqlSlices[0].text
);
expect(sqlSlices[0].startLine).toBe(1);
expect(sqlSlices[0].endLine).toBe(1);
expect(sqlSlices[1].text).toBe('SELECT * FROM tb;');
expect(sql.slice(sqlSlices[1].startIndex, sqlSlices[1].endIndex + 1)).toBe(
sqlSlices[1].text
);
expect(sqlSlices[1].startLine).toBe(2);
expect(sqlSlices[1].endLine).toBe(2);
});
test('Split sql with errors', () => {
const sql = 'SHOW TABLES;\nSELECT * FOM tb;';
const sqlSlices = flinkParser.splitSQLByStatement(sql);
expect(sqlSlices).toBeNull();
});
});

View File

@ -8,7 +8,7 @@ describe('Flink SQL Listener Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new FlinkSQL(); const parser = new FlinkSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Listener enterTableName', async () => { test('Listener enterTableName', async () => {
let result = ''; let result = '';
@ -19,7 +19,7 @@ describe('Flink SQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree); await parser.listen(listenTableName as ParseTreeListener, parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('Flink SQL Visitor Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new FlinkSQL(); const parser = new FlinkSQL();
const parserTree = parser.parse(sql, (error) => { const parseTree = parser.parse(sql, (error) => {
console.log('Parse error:', error); console.log('Parse error:', error);
}); });
@ -25,7 +25,7 @@ describe('Flink SQL Visitor Tests', () => {
}; };
} }
const visitor: any = new MyVisitor(); const visitor: any = new MyVisitor();
visitor.visit(parserTree); visitor.visit(parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });

View File

@ -7,7 +7,7 @@ describe('Generic SQL Listener Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new GenericSQL(); const parser = new GenericSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Listener enterTableName', async () => { test('Listener enterTableName', async () => {
let result = ''; let result = '';
@ -18,7 +18,7 @@ describe('Generic SQL Listener Tests', () => {
} }
const listenTableName: any = new MyListener(); const listenTableName: any = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree); await parser.listen(listenTableName as ParseTreeListener, parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('Generic SQL Visitor Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new GenericSQL(); const parser = new GenericSQL();
const parserTree = parser.parse(sql, (error) => { const parseTree = parser.parse(sql, (error) => {
console.log('Parse error:', error); console.log('Parse error:', error);
}); });
@ -23,7 +23,7 @@ describe('Generic SQL Visitor Tests', () => {
}; };
} }
const visitor = new MyVisitor(); const visitor = new MyVisitor();
visitor.visit(parserTree); visitor.visit(parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });

View File

@ -8,7 +8,7 @@ describe('HiveSQL Listener Tests', () => {
test('Listener enterSelectList', async () => { test('Listener enterSelectList', async () => {
const expectTableName = 'username'; const expectTableName = 'username';
const sql = `select ${expectTableName} from tablename where inc_day='20190601' limit 1000;`; const sql = `select ${expectTableName} from tablename where inc_day='20190601' limit 1000;`;
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
let result = ''; let result = '';
class MyListener implements HiveSqlParserListener { class MyListener implements HiveSqlParserListener {
@ -18,12 +18,12 @@ describe('HiveSQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree as ProgramContext); await parser.listen(listenTableName as ParseTreeListener, parseTree as ProgramContext);
expect(result).toBe(expectTableName.toUpperCase()); expect(result).toBe(expectTableName.toUpperCase());
}); });
test('Listener enterCreateTable', async () => { test('Listener enterCreateTable', async () => {
const sql = `drop table table_name;`; const sql = `drop table table_name;`;
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
let result = ''; let result = '';
class MyListener implements HiveSqlParserListener { class MyListener implements HiveSqlParserListener {
enterDropTableStatement(ctx) { enterDropTableStatement(ctx) {
@ -32,7 +32,7 @@ describe('HiveSQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree as ProgramContext); await parser.listen(listenTableName as ParseTreeListener, parseTree as ProgramContext);
expect(result).toBe('DROPTABLETABLE_NAME'); expect(result).toBe('DROPTABLETABLE_NAME');
}); });
}); });

View File

@ -8,7 +8,7 @@ describe('HiveSQL Visitor Tests', () => {
const sql = `select citycode,tc,inc_day from ${expectTableName} where inc_day='20190501' limit 100;`; const sql = `select citycode,tc,inc_day from ${expectTableName} where inc_day='20190501' limit 100;`;
const parser = new HiveSQL(); const parser = new HiveSQL();
const parserTree = parser.parse(sql, (error) => { const parseTree = parser.parse(sql, (error) => {
console.log('Parse error:', error); console.log('Parse error:', error);
}); });
@ -25,7 +25,7 @@ describe('HiveSQL Visitor Tests', () => {
} }
const visitor = new MyVisitor(); const visitor = new MyVisitor();
visitor.visit(parserTree as ProgramContext); visitor.visit(parseTree as ProgramContext);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });

View File

@ -8,7 +8,7 @@ describe('PostgresSQL Listener Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new PostgresSQL(); const parser = new PostgresSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Listener enterTableName', async () => { test('Listener enterTableName', async () => {
let result = ''; let result = '';
@ -19,7 +19,7 @@ describe('PostgresSQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree); await parser.listen(listenTableName as ParseTreeListener, parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('Generic SQL Visitor Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new PostgresSQL(); const parser = new PostgresSQL();
const parserTree = parser.parse(sql, (error) => { const parseTree = parser.parse(sql, (error) => {
console.log('Parse error:', error); console.log('Parse error:', error);
}); });
@ -26,7 +26,7 @@ describe('Generic SQL Visitor Tests', () => {
} }
} }
const visitor: any = new MyVisitor(); const visitor: any = new MyVisitor();
visitor.visit(parserTree); visitor.visit(parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });

View File

@ -7,7 +7,7 @@ describe('PLSQL Listener Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new PLSQL(); const parser = new PLSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Listener enterTableName', async () => { test('Listener enterTableName', async () => {
let result = ''; let result = '';
@ -18,7 +18,7 @@ describe('PLSQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree); await parser.listen(listenTableName as ParseTreeListener, parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('PLSQL Visitor Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new PLSQL(); const parser = new PLSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Visitor visitTable_ref_list', () => { test('Visitor visitTable_ref_list', () => {
let result = ''; let result = '';
@ -20,7 +20,7 @@ describe('PLSQL Visitor Tests', () => {
}; };
} }
const visitor: any = new MyVisitor(); const visitor: any = new MyVisitor();
visitor.visit(parserTree); visitor.visit(parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });

View File

@ -7,7 +7,7 @@ describe('Spark SQL Listener Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new SparkSQL(); const parser = new SparkSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Listener exitRelationPrimary', () => { test('Listener exitRelationPrimary', () => {
let result = ''; let result = '';
@ -18,7 +18,7 @@ describe('Spark SQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
parser.listen(listenTableName as ParseTreeListener, parserTree); parser.listen(listenTableName as ParseTreeListener, parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('Spark SQL Visitor Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new SparkSQL(); const parser = new SparkSQL();
const parserTree = parser.parse(sql, (error) => { const parseTree = parser.parse(sql, (error) => {
console.log('Parse error:', error); console.log('Parse error:', error);
}); });
@ -25,7 +25,7 @@ describe('Spark SQL Visitor Tests', () => {
}; };
} }
const visitor = new MyVisitor(); const visitor = new MyVisitor();
visitor.visit(parserTree); visitor.visit(parseTree);
expect(visitor.result).toBe(expectTableName); expect(visitor.result).toBe(expectTableName);
}); });

View File

@ -7,7 +7,7 @@ describe('trino SQL Listener Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new trinoSQL(); const parser = new trinoSQL();
const parserTree = parser.parse(sql); const parseTree = parser.parse(sql);
test('Listener enterTableName', async () => { test('Listener enterTableName', async () => {
let result = ''; let result = '';
@ -18,7 +18,7 @@ describe('trino SQL Listener Tests', () => {
} }
const listenTableName = new MyListener(); const listenTableName = new MyListener();
await parser.listen(listenTableName as ParseTreeListener, parserTree); await parser.listen(listenTableName as ParseTreeListener, parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });
}); });

View File

@ -7,7 +7,7 @@ describe('trino SQL Visitor Tests', () => {
const sql = `select id,name,sex from ${expectTableName};`; const sql = `select id,name,sex from ${expectTableName};`;
const parser = new trinoSQL(); const parser = new trinoSQL();
const parserTree = parser.parse(sql, (error) => { const parseTree = parser.parse(sql, (error) => {
console.log('Parse error:', error); console.log('Parse error:', error);
}); });
@ -22,7 +22,7 @@ describe('trino SQL Visitor Tests', () => {
}; };
} }
const visitor: any = new MyVisitor(); const visitor: any = new MyVisitor();
visitor.visit(parserTree); visitor.visit(parseTree);
expect(result).toBe(expectTableName); expect(result).toBe(expectTableName);
}); });