Skip to content

Commit

Permalink
Provide diagnostics for cycles in alg
Browse files Browse the repository at this point in the history
  • Loading branch information
vetlek committed Aug 14, 2023
1 parent 6e76a1d commit 2329000
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 1 deletion.
38 changes: 38 additions & 0 deletions server/src/language-service/diagnosticsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
Attribute,
SepticObject,
defaultRefValidationFunction,
Alg,
findAlgCycles,
} from "../septic";
import { SettingsManager } from "../settings";
import { isPureJinja } from "../util";
Expand Down Expand Up @@ -507,3 +509,39 @@ function getDiagnosticCodes(codes: string): string[] {
});
return diagnosticCodes;
}

export function validateAlgCycles(
refProvider: SepticReferenceProvider,
doc: ITextDocument
): Diagnostic[] {
const diagnostics: Diagnostic[] = [];
for (let cycle of refProvider.getCycles()) {
let cycleStr = [...cycle.nodes, cycle.nodes[0]]
.map((node) => node.name)
.join("->");
for (let node of cycle.nodes) {
let xvrRefs = refProvider.getXvrRefs(node.name);
if (!xvrRefs) {
continue;
}
let xvrObjs = xvrRefs.filter((xvr) => xvr.obj);
if (!xvrObjs.length) {
continue;
}
if (xvrObjs[0].location.uri === doc.uri) {
diagnostics.push(
createDiagnostic(
DiagnosticSeverity.Error,
{
start: doc.positionAt(xvrObjs[0].location.start),
end: doc.positionAt(xvrObjs[0].location.end),
},
`Cycle in algs detected for CalcPvr. ${cycleStr}`,
DiagnosticCode.W101
)
);
}
}
}
return diagnostics;
}
4 changes: 4 additions & 0 deletions server/src/septic/reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Cycle } from "./cycle";
import { SepticObject } from "./septicElements";

export interface SepticReference {
Expand Down Expand Up @@ -52,4 +53,7 @@ export interface SepticReferenceProvider {
name: string,
validationFunction: RefValidationFunction
): boolean;
getCalcPvrs(): SepticObject[];
detectCycles(): void;
getCycles(): Cycle[];
}
27 changes: 27 additions & 0 deletions server/src/septic/septicCnfg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import {
createSepticReference,
} from "./reference";
import { removeSpaces } from "../util";
import { Alg, Cycle, findAlgCycles } from "./cycle";

export class SepticCnfg implements SepticReferenceProvider {
public objects: SepticObject[];
public comments: SepticComment[];
public cycles: Cycle[] = [];
private xvrRefs = new Map<string, SepticReference[]>();
private xvrRefsExtracted = false;
public uri: string = "";
Expand Down Expand Up @@ -107,6 +109,31 @@ export class SepticCnfg implements SepticReferenceProvider {
return undefined;
}

public getCalcPvrs(): SepticObject[] {
return this.objects.filter((obj) => obj.isType("CalcPvr"));
}

public getCycles(): Cycle[] {
return this.cycles;
}

public detectCycles(): void {
let calcPvrs = this.getCalcPvrs();
let algs: Alg[] = [];
for (let calcPvr of calcPvrs) {
let alg = calcPvr.getAttribute("Alg");
let content = alg?.getAttrValue()?.getValue();
if (!content || !calcPvr.identifier?.name) {
continue;
}
algs.push({
calcPvrName: calcPvr.identifier?.name!,
content: content,
});
}
this.cycles = findAlgCycles(algs);
}

private extractXvrRefs(): void {
if (this.xvrRefsExtracted) {
return;
Expand Down
37 changes: 36 additions & 1 deletion server/src/septic/septicScgContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { SepticObject } from "./septicElements";
import { SepticConfigProvider } from "../language-service/septicConfigProvider";
import { SepticCnfg } from "./septicCnfg";
import { Alg, Cycle, findAlgCycles } from "./cycle";

export interface ScgConfig {
outputfile?: string;
Expand Down Expand Up @@ -43,6 +44,7 @@ export interface ScgTemplate {
export class ScgContext implements SepticReferenceProvider {
public name: string;
public filePath: string;
public cycles: Cycle[] = [];

private cnfgProvider: SepticConfigProvider;
private cnfgCache = new Map<string, SepticCnfg | undefined>();
Expand Down Expand Up @@ -99,7 +101,7 @@ export class ScgContext implements SepticReferenceProvider {
if (!cnfg) {
return;
}
this.cnfgCache.set(cnfg!.uri, cnfg);
this.cnfgCache.set(cnfg.uri, cnfg);
})
);
}
Expand Down Expand Up @@ -147,4 +149,37 @@ export class ScgContext implements SepticReferenceProvider {
}
return xvrObjs;
}

public getCalcPvrs(): SepticObject[] {
let calcPvrs: SepticObject[] = [];
for (const file of this.files) {
let cnfg = this.cnfgCache.get(file);
if (!cnfg) {
continue;
}
calcPvrs.push(...cnfg.getCalcPvrs());
}
return calcPvrs;
}

public getCycles(): Cycle[] {
return this.cycles;
}

public detectCycles(): void {
let calcPvrs = this.getCalcPvrs();
let algs: Alg[] = [];
for (let calcPvr of calcPvrs) {
let alg = calcPvr.getAttribute("Alg");
let content = alg?.getAttrValue()?.getValue();
if (!content || !calcPvr.identifier?.name) {
continue;
}
algs.push({
calcPvrName: calcPvr.identifier?.name!,
content: content,
});
}
this.cycles = findAlgCycles(algs);
}
}
2 changes: 2 additions & 0 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ let hasDiagnosticRelatedInformationCapability = false;

async function publishDiagnosticsContext(context: ScgContext): Promise<void> {
await context.load();
context.detectCycles();
const diagnosticsPromises = context.files.map(async (file) => {
let doc = await documentProvider.getDocument(file);
if (!doc) {
Expand All @@ -69,6 +70,7 @@ async function publishDiagnosticsContext(context: ScgContext): Promise<void> {
}

async function publishDiagnosticsCnfg(cnfg: SepticCnfg): Promise<void> {
cnfg.detectCycles();
let doc = await documentProvider.getDocument(cnfg.uri);
if (!doc) {
return;
Expand Down
49 changes: 49 additions & 0 deletions server/src/test/diagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
identifierDiagnostics,
getDiagnostics,
disableDiagnosticRegex,
validateAlgCycles,
} from "../language-service/diagnosticsProvider";
import { parseSeptic } from "../septic";
import { MockDocument } from "./util";
Expand Down Expand Up @@ -234,3 +235,51 @@ describe("Test disabling of diagnostics", () => {
expect(diag.length).to.equal(1);
});
});

describe("Test validation of cycles", () => {
it("Expect no diagnostics for non-cyclic calcs", () => {
const text = `
Evr: Test1
Evr: Test2
CalcPvr: Test1
Alg= "Test2 + 1"
`;

const doc = new MockDocument(text);
const cnfg = parseSeptic(doc.getText());
cnfg.detectCycles();
let diag = validateAlgCycles(cnfg, doc);
expect(diag.length).to.equal(0);
});

it("Expect diagnostics for self cycle", () => {
const text = `
Evr: Test1
CalcPvr: Test1
Alg= "Test1 + 1"
`;

const doc = new MockDocument(text);
const cnfg = parseSeptic(doc.getText());
cnfg.detectCycles();
let diag = validateAlgCycles(cnfg, doc);
expect(diag.length).to.equal(1);
});

it("Expect diagnostics for cycle of length 2", () => {
const text = `
Evr: Test1
Evr: Test2
CalcPvr: Test1
Alg= "Test2 + 1"
CalcPvr: Test2
Alg= "Test1 - 1"
`;

const doc = new MockDocument(text);
const cnfg = parseSeptic(doc.getText());
cnfg.detectCycles();
let diag = validateAlgCycles(cnfg, doc);
expect(diag.length).to.equal(2);
});
});

0 comments on commit 2329000

Please sign in to comment.