Skip to content

Commit

Permalink
Report errors from antlr through logger (#46)
Browse files Browse the repository at this point in the history
Mismatched or extraneous input encountered during parsing will
produce error messages that include the location of the error.
Two tests are added to FSHImporter.test.ts for these errors.
  • Loading branch information
mint-thompson authored and cmoesel committed Dec 6, 2019
1 parent 9ac08ce commit 550aa39
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
27 changes: 27 additions & 0 deletions src/import/FSHErrorListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ErrorListener } from 'antlr4/error';
import { logger } from '../utils/FSHLogger';
import { Recognizer, Token } from 'antlr4';

export class FSHErrorListener extends ErrorListener {
constructor(readonly file: string) {
super();
}

syntaxError(
recognizer: Recognizer,
offendingSymbol: Token,
line: number,
column: number,
msg: string
): void {
logger.error(msg, {
file: this.file,
location: {
startLine: line,
startColumn: column + 1,
endLine: line,
endColumn: column + offendingSymbol.text.length
}
});
}
}
14 changes: 12 additions & 2 deletions src/import/importText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FSHParser } from './generated/FSHParser';
import { DocContext } from './parserContexts';
import { FSHImporter } from './FSHImporter';
import { FSHDocument } from './FSHDocument';
import { FSHErrorListener } from './FSHErrorListener';

/**
* Parses a text string as a FSHDocument.
Expand All @@ -13,17 +14,26 @@ import { FSHDocument } from './FSHDocument';
*/
export function importText(text: string, file?: string): FSHDocument {
const importer = new FSHImporter(file);
return importer.visitDoc(parseDoc(text));
return importer.visitDoc(parseDoc(text, file));
}

// NOTE: Since the ANTLR parser/lexer is JS (not typescript), we need to use some ts-ignore here.
function parseDoc(input: string): DocContext {
function parseDoc(input: string, file?: string): DocContext {
const chars = new InputStream(input);
const lexer = new FSHLexer(chars);
const listener = new FSHErrorListener(file);
// @ts-ignore
lexer.removeErrorListeners();
// @ts-ignore
lexer.addErrorListener(listener);
// @ts-ignore
const tokens = new CommonTokenStream(lexer);
const parser = new FSHParser(tokens);
// @ts-ignore
parser.removeErrorListeners();
// @ts-ignore
parser.addErrorListener(listener);
// @ts-ignore
parser.buildParseTrees = true;
// @ts-ignore
return parser.doc() as DocContext;
Expand Down
29 changes: 29 additions & 0 deletions test/import/FSHImporter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { importText, FSHImporter, FSHDocument } from '../../src/import';
import { logger } from '../../src/utils/FSHLogger';

describe('FSHImporter', () => {
let mockWriter: jest.SpyInstance<boolean, [any, string, ((error: Error) => void)?]>;

beforeAll(() => {
mockWriter = jest.spyOn(logger.transports[0], 'write');
});

it('should default filename to blank string', () => {
const input = '';
const result = importText(input);
Expand Down Expand Up @@ -33,4 +40,26 @@ describe('FSHImporter', () => {
const result2 = visitor.visitDoc({ entity: () => [] });
expect(result2).toBeUndefined();
});

it('should report mismatched input errors from antlr', () => {
const input = `
Profile: MismatchedPizza
Pizza: Large
`;
importText(input, 'Pizza.fsh');
expect(mockWriter.mock.calls[mockWriter.mock.calls.length - 1][0].message).toMatch(
/File: Pizza\.fsh.*Line 3\D.*Column 5\D.*Line 3\D.*Column 10\D/s
);
});

it('should report extraneous input errors from antlr', () => {
const input = `
Profile: Something Spaced
Parent: Spacious
`;
importText(input, 'Space.fsh');
expect(mockWriter.mock.calls[mockWriter.mock.calls.length - 1][0].message).toMatch(
/File: Space\.fsh.*Line 2\D.*Column 24\D.*Line 2\D.*Column 29\D/s
);
});
});

0 comments on commit 550aa39

Please sign in to comment.