Skip to content

Commit

Permalink
Merge pull request #71 from MeasureAuthoringTool/feature/grammar-erro…
Browse files Browse the repository at this point in the history
…r-reporting

Report Grammar Errors Relative to Line Position and Disable non-Grammar Error Checking
  • Loading branch information
jkotanchik-SB authored Apr 12, 2022
2 parents 622d0b2 + d94bb52 commit 341184e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 35 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
24 changes: 12 additions & 12 deletions src/CqlAntlr.ts
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -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;
}

Expand All @@ -32,7 +34,7 @@ class CqlAntlr {
parameters: [],
identifiers: [],
expressionDefinitions: [],
errors:[]
errors: [],
};
}

Expand All @@ -56,5 +58,3 @@ class CqlAntlr {
}

export default CqlAntlr;


6 changes: 3 additions & 3 deletions src/CqlIdentifierCreator.ts
Original file line number Diff line number Diff line change
@@ -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<CqlIdentifier> {
Expand All @@ -10,7 +10,7 @@ export default class CqlIdentifierCreator extends CreatorBase<CqlIdentifier> {
}

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;
Expand Down
33 changes: 22 additions & 11 deletions src/CustomErrorListener.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
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<Token> {

constructor(private cqlResult: CqlResult) {
}
constructor(private cqlResult: CqlResult) {}

syntaxError<T extends Token>(
recognizer: Recognizer<T, ParserATNSimulator>,
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,
});
}
}
Expand Down
20 changes: 12 additions & 8 deletions test/CqlAntlr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand All @@ -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", () => {
Expand Down Expand Up @@ -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 => {
Expand Down

0 comments on commit 341184e

Please sign in to comment.