From 8c860709a55183bff463dd5dae2922fe89b82e1b Mon Sep 17 00:00:00 2001 From: Joseph Kotanchik Date: Tue, 12 Apr 2022 11:28:49 -0400 Subject: [PATCH 1/2] Disable non-grammar rules Report grammar error positions relative to line position instead of absolute character count --- src/CqlAntlr.ts | 24 ++++++++++++------------ src/CustomErrorListener.ts | 30 +++++++++++++++++++----------- test/CqlAntlr.test.ts | 20 ++++++++++++-------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/src/CqlAntlr.ts b/src/CqlAntlr.ts index 2d2c403..77cbe30 100644 --- a/src/CqlAntlr.ts +++ b/src/CqlAntlr.ts @@ -1,15 +1,13 @@ -import {CharStreams, CommonTokenStream} from "antlr4ts"; -import {CodePointCharStream} from "antlr4ts/CodePointCharStream"; -import {ParseTreeWalker} from "antlr4ts/tree"; -import {cqlLexer, cqlParser, LibraryContext, cqlListener} from "../generated"; +import { CharStreams, CommonTokenStream } from "antlr4ts"; +import { CodePointCharStream } from "antlr4ts/CodePointCharStream"; +import { ParseTreeWalker } from "antlr4ts/tree"; +import { cqlLexer, cqlParser, LibraryContext, cqlListener } from "../generated"; import CqlAntlrListener from "./CqlAntlrListener"; import CqlResult from "./dto/CqlResult"; import CustomErrorListener from "./CustomErrorListener"; -import CqlExpressionVisitor from "./CqlExpressionVisitor"; class CqlAntlr { - constructor(private cql: string) { - } + constructor(private cql: string) {} parse(): CqlResult { const result = CqlAntlr.initCqlResult(); @@ -18,8 +16,12 @@ class CqlAntlr { const listener: cqlListener = new CqlAntlrListener(result); ParseTreeWalker.DEFAULT.walk(listener, tree); - const cqlExpressionVisitor = new CqlExpressionVisitor(result); - cqlExpressionVisitor.visit(tree); + /** + * Disabled. Only partially implemented and would be + * a duplicate of checks performed by the CQL-to-ELM Translator. + */ + // const cqlExpressionVisitor = new CqlExpressionVisitor(result); + // cqlExpressionVisitor.visit(tree); return result; } @@ -32,7 +34,7 @@ class CqlAntlr { parameters: [], identifiers: [], expressionDefinitions: [], - errors:[] + errors: [], }; } @@ -56,5 +58,3 @@ class CqlAntlr { } export default CqlAntlr; - - diff --git a/src/CustomErrorListener.ts b/src/CustomErrorListener.ts index dd3c9c6..b434db2 100644 --- a/src/CustomErrorListener.ts +++ b/src/CustomErrorListener.ts @@ -1,27 +1,35 @@ -import {ANTLRErrorListener} from "antlr4ts"; -import {Recognizer} from "antlr4ts/Recognizer"; -import {Token} from "antlr4ts/Token"; -import {ParserATNSimulator} from "antlr4ts/atn/ParserATNSimulator"; +import { ANTLRErrorListener } from "antlr4ts"; +import { Recognizer } from "antlr4ts/Recognizer"; +import { Token } from "antlr4ts/Token"; +import { ParserATNSimulator } from "antlr4ts/atn/ParserATNSimulator"; import CqlResult from "./dto/CqlResult"; +/** + * Fires on grammar errors. + */ export default class CustomErrorListener implements ANTLRErrorListener { - - constructor(private cqlResult: CqlResult) { - } + constructor(private cqlResult: CqlResult) {} syntaxError( recognizer: Recognizer, offendingSymbol: T | undefined, line: number, charPositionInLine: number, - msg: string): void { + msg: string + ): void { if (offendingSymbol) { this.cqlResult.errors.push({ text: offendingSymbol.text, - start: {line, position: offendingSymbol.startIndex}, - stop: {line, position: offendingSymbol.stopIndex}, + start: { line, position: offendingSymbol.charPositionInLine }, + stop: { + line, + position: + offendingSymbol.charPositionInLine + + (offendingSymbol.stopIndex - offendingSymbol.startIndex) + + 1, // plus 1 to ensure full text is included in Ace Editor highlight + }, name: offendingSymbol.text, - message: msg + message: msg, }); } } diff --git a/test/CqlAntlr.test.ts b/test/CqlAntlr.test.ts index c4b6eec..66843a3 100644 --- a/test/CqlAntlr.test.ts +++ b/test/CqlAntlr.test.ts @@ -7,10 +7,10 @@ import { cqlWithUsedContext, cqlFluentFunctions, relatedContextRetrieve, - aggregateQuery + aggregateQuery, } from "./testCql"; import { CqlAntlr } from "../src"; -import CqlResult from "../src/dto/CqlResult" +import CqlResult from "../src/dto/CqlResult"; describe("test antlr", () => { it("parse", () => { @@ -36,17 +36,21 @@ describe("test antlr", () => { expect(cqlResult.codes.length).toBe(1); expect(cqlResult.codeSystems.length).toBe(3); - expect(cqlResult.errors.length).toBe(4); + expect(cqlResult.errors.length).toBe(3); expect(cqlResult.errors[0].name).toBe("includess"); - expect(cqlResult.errors[0].message).toContain("extraneous input 'includess' expecting"); - expect(cqlResult.errors[0].start).toEqual({line: 6, position: 180}); - expect(cqlResult.errors[0].stop).toEqual({line: 6, position: 188}); + expect(cqlResult.errors[0].message).toContain( + "extraneous input 'includess' expecting" + ); + expect(cqlResult.errors[0].start).toEqual({ line: 6, position: 0 }); + expect(cqlResult.errors[0].stop).toEqual({ line: 6, position: 9 }); expect(cqlResult.errors[1].name).toBe("valuesetss"); expect(cqlResult.errors[2].name).toBe("Interval"); - expect(cqlResult.errors[2].message).toContain("missing {QUOTEDIDENTIFIER, IDENTIFIER, DELIMITEDIDENTIFIER} at 'Interval'"); + expect(cqlResult.errors[2].message).toContain( + "missing {QUOTEDIDENTIFIER, IDENTIFIER, DELIMITEDIDENTIFIER} at 'Interval'" + ); }); it("should recognize valid parameter", () => { @@ -87,7 +91,7 @@ describe("test antlr", () => { it("should recognize cql 1.5 Related Context Retrieve", (): void => { const cqlAntlr = new CqlAntlr(relatedContextRetrieve); const cqlResult: CqlResult = cqlAntlr.parse(); - expect(cqlResult.errors.length).toEqual(1); + expect(cqlResult.errors.length).toEqual(0); }); it("should recognize cql 1.5 aggregate clause", (): void => { From d94bb525fd66476cb3f3a7e2ddd0caae7918e659 Mon Sep 17 00:00:00 2001 From: Joseph Kotanchik Date: Tue, 12 Apr 2022 14:56:03 -0400 Subject: [PATCH 2/2] Bump package version --- package.json | 2 +- src/CqlIdentifierCreator.ts | 6 +++--- src/CustomErrorListener.ts | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8278a39..91543e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@madie/cql-antlr-parser", - "version": "1.0.0", + "version": "1.0.1", "description": "Antlr Parsing of CQL in typescript", "publishConfig": { "access": "public" diff --git a/src/CqlIdentifierCreator.ts b/src/CqlIdentifierCreator.ts index 3518352..27d7444 100644 --- a/src/CqlIdentifierCreator.ts +++ b/src/CqlIdentifierCreator.ts @@ -1,7 +1,7 @@ -import {ParserRuleContext} from "antlr4ts/ParserRuleContext"; +import { ParserRuleContext } from "antlr4ts/ParserRuleContext"; import CreatorBase from "./CreatorBase"; import CqlVersionCreator from "./CqlVersionCreator"; -import {cqlLexer} from "../generated"; +import { cqlLexer } from "../generated"; import CqlIdentifier from "./dto/CqlIdentifier"; export default class CqlIdentifierCreator extends CreatorBase { @@ -10,7 +10,7 @@ export default class CqlIdentifierCreator extends CreatorBase { } protected build(): CqlIdentifier { - CqlVersionCreator.setNameVersion(this.ctx.children, this.cqlDao); + CqlVersionCreator.setNameVersion(this.ctx?.children, this.cqlDao); this.cqlDao.name = this.findChildText(cqlLexer.IDENTIFIER); return this.cqlDao; diff --git a/src/CustomErrorListener.ts b/src/CustomErrorListener.ts index b434db2..b3d0925 100644 --- a/src/CustomErrorListener.ts +++ b/src/CustomErrorListener.ts @@ -20,7 +20,10 @@ export default class CustomErrorListener implements ANTLRErrorListener { if (offendingSymbol) { this.cqlResult.errors.push({ text: offendingSymbol.text, - start: { line, position: offendingSymbol.charPositionInLine }, + start: { + line, + position: offendingSymbol.charPositionInLine, + }, stop: { line, position: