Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions src/tests/dspf.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, describe, it } from "vitest";
import { DdsLineRange, DisplayFile, FieldInfo } from "../ui/dspf";
import { Conditional, DdsLineRange, DisplayFile, DisplayFileIndicators, FieldInfo } from "../ui/dspf";

describe('DisplayFile tests', () => {

Expand All @@ -16,12 +16,14 @@ describe('DisplayFile tests', () => {
` A R GLOBAL `,
` A SLNO(04) `,
` A 1 3'---' `,
` A R FORM1 `,
` A R FORM1 `,
` A SLNO(06) `,
` A FLD0101 10A B 3 5 `,
` A 20 DSPATR(PR) `,
` A COLOR(YLW) `,
` A FLD0102 10 B 3 5 `,
` A R FORM2 `,
` A 30 SLNO(02) `,
];

it('getRangeForFormat', () => {
Expand Down Expand Up @@ -78,28 +80,59 @@ describe('DisplayFile tests', () => {
{
name: "COLOR",
value: "BLU",
conditions: []
conditional: new Conditional()
},
{
name: "DSPATR",
value: "PR",
conditions: []
conditional: new Conditional(` 31`)
}
);

lines = DisplayFile.getLinesForField(field);
expect(lines.length).toBe(3);
expect(lines[0]).toBe(` A 4 10'Some text'`);
expect(lines[1]).toBe(` A COLOR(BLU)`);
expect(lines[2]).toBe(` A DSPATR(PR)`);
expect(lines[2]).toBe(` A 31 DSPATR(PR)`);

});

it('getLinesForFormat', () => {
let dds = new DisplayFile();
dds.parse(dspf1);
let lines = DisplayFile.getLinesForFormat(dds.formats[5]);
expect(lines.length).toBe(2);
expect(lines[1]).toBe(` A 30 SLNO(02)`);
});

it('No duplicate RecordInfo', () => {
let dds = new DisplayFile();
dds.parse(dspf1);
let names = dds.formats.map(rcd => rcd.name);
expect(new Set(names).size).toBe(names.length);
});

it('Test for Conditional class', () => {

let cond = new Conditional();
cond.push(` N10 11N12`);

expect(cond.getConditions().length).toBe(1);
expect(cond.getConditions().at(0)?.indicators.length).toBe(3);

cond.push(`O 20 21`);

expect(cond.getConditions().length).toBe(2);
expect(cond.getConditions().at(1)?.indicators.length).toBe(2);

let indicators = new DisplayFileIndicators();
indicators.set(11, true);
expect(cond.isActive(indicators)).toBeTruthy;
indicators.set(10, true);
expect(cond.isActive(indicators)).toBeFalsy;
indicators.set(20, true);
expect(cond.isActive(indicators)).toBeTruthy;

});

});
192 changes: 136 additions & 56 deletions src/ui/dspf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class DisplayFile {
this.currentField.keywords.push({
name: `DATE`,
value: undefined,
conditions: []
conditional: new Conditional()
});
break;
case `T`: //Time
Expand All @@ -155,17 +155,15 @@ export class DisplayFile {
this.currentField.keywords.push({
name: `TIME`,
value: undefined,
conditions: []
conditional: new Conditional()
});
break;
default:
this.currentField.primitiveType = `char`;
break;
}

this.currentField.conditions.push(
...DisplayFile.parseConditionals(conditionals)
);
this.currentField.conditional.push(conditionals);
}
this.HandleKeywords(keywords, conditionals);
}
Expand All @@ -178,9 +176,7 @@ export class DisplayFile {
this.currentField.length = this.currentField.value.length;
this.currentField.displayType = `const`;

this.currentField.conditions.push(
...DisplayFile.parseConditionals(conditionals)
);
this.currentField.conditional.push(conditionals);
}
}
this.HandleKeywords(keywords, conditionals);
Expand Down Expand Up @@ -227,42 +223,11 @@ export class DisplayFile {

}

static parseConditionals(conditionColumns: string): Conditional[] {
if (conditionColumns.trim() === "") {return [];}

/** @type {Conditional[]} */
let conditionals = [];

//TODO: something with condition
//const condition = conditionColumns.substring(0, 1); //A (and) or O (or)

let current = "";
let negate = false;
let indicator = 0;

let cIndex = 1;

while (cIndex <= 7) {
current = conditionColumns.substring(cIndex, cIndex + 3);

if (current.trim() !== "") {
negate = (conditionColumns.substring(cIndex, cIndex + 1) === "N");
indicator = Number(conditionColumns.substring(cIndex + 1, cIndex + 3));

conditionals.push({indicator, negate});
}

cIndex += 3;
}

return conditionals;
}

static parseKeywords(keywordStrings: string[], conditionalStrings?: { [line: number]: string }) {
let result: { value: string, keywords: Keyword[], conditions: Conditional[] } = {
let result: { value: string, keywords: Keyword[], conditional: Conditional } = {
value: ``,
keywords: [],
conditions: []
conditional: new Conditional()
};

const newLineMark = `~`;
Expand Down Expand Up @@ -330,7 +295,7 @@ export class DisplayFile {
result.keywords.push({
name: word.toUpperCase(),
value: innerValue.length > 0 ? innerValue : undefined,
conditions: conditionals ? DisplayFile.parseConditionals(conditionals) : []
conditional: new Conditional(conditionals)
});

word = ``;
Expand Down Expand Up @@ -381,10 +346,7 @@ export class DisplayFile {
}

for (const keyword of field.keywords) {
// TODO: support conditions
newLines.push(
` A ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`,
);
newLines.push(...keyword.conditional.getLinesWithCondition(` A ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`));
}

return newLines;
Expand Down Expand Up @@ -436,7 +398,6 @@ export class DisplayFile {
return { newLines, range };
}

// TODO: test cases
static getLinesForFormat(recordFormat: RecordInfo): string[] {
const lines: string[] = [];

Expand All @@ -445,10 +406,7 @@ export class DisplayFile {
}

for (const keyword of recordFormat.keywords) {
// TODO: support conditions
lines.push(
` A ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`,
);
lines.push(...keyword.conditional.getLinesWithCondition(` A ${keyword.name}${keyword.value ? `(${keyword.value})` : ``}`));
}

return lines;
Expand Down Expand Up @@ -562,7 +520,7 @@ export class RecordInfo {
}
}

export interface Keyword { name: string, value?: string, conditions: Conditional[] };
export interface Keyword { name: string, value?: string, conditional: Conditional };

export type DisplayType = "input" | "output" | "both" | "const" | "hidden";

Expand All @@ -575,7 +533,7 @@ export class FieldInfo {
public decimals: number = 0;
public position: { x: number, y: number } = { x: 0, y: 0 };
public keywordStrings: { keywordLines: string[], conditionalLines: { [lineIndex: number]: string } } = { keywordLines: [], conditionalLines: {} };
public conditions: Conditional[] = [];
public conditional: Conditional = new Conditional();
public keywords: Keyword[] = [];

constructor(public startRange: number, public name?: string) {}
Expand All @@ -591,7 +549,129 @@ export class FieldInfo {
}
}

export interface Conditional {
indicator: number,
negate: boolean
export interface Condition {
indicators: Indicator[];
}

export interface Indicator {
indicator: number,
negate: boolean
}

export class Conditional {
private conditions: Condition[] = [{
indicators: []
}];

constructor(indicatorStr?: string) {
if (indicatorStr !== undefined) {
this.push(indicatorStr);
}
}

push(indicatorStr: string) {
if (indicatorStr.substring(0, 1) === `O` && this.conditions[this.conditions.length - 1].indicators.length > 0) {
if (this.conditions.length >= 9) {
throw new Error("Too many conditions");
}
this.conditions.push({indicators: []});
}

let cIndex = 1;
let current = ``;
let negate = false;
let indicator = 0;

while (cIndex <= 7) {
current = indicatorStr.substring(cIndex, cIndex + 3);

if (current.trim() !== "") {
negate = (indicatorStr.substring(cIndex, cIndex + 1) === "N");
indicator = Number(indicatorStr.substring(cIndex + 1, cIndex + 3));
if (indicator !== 0) {
if (this.conditions[this.conditions.length - 1].indicators.length >= 9) {
throw new Error("Too many option indicators specified for one condition");
}
this.conditions[this.conditions.length - 1].indicators.push({
indicator: indicator,
negate: negate
});
}
}

cIndex += 3;
}
}

getConditions(): Condition[] {
return this.conditions;
}
Comment on lines +606 to +608
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand this API very well. It returns the following interface as an array:

interface Condition {
    indicators: Indicator[];
}

but I don't quite understand it, and it could be me. Is this because each condition line can have 3 indicators, and each line is actually a unique condition (because you can use and or or when testing each condition right?)

Perhaps condition also needs an additional property to handle when O is specified?

interface Condition {
    indicators: Indicator[];
    operator?: `and`|`or`; //and is default?
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, here is some DDS for a constant:


     A  01 02N03                        8  3'One, Two, not Three'
     A  01
     AA 02

Does this read as three conditions:

  1. The first with three indicators, the last negated
  2. The second with one indicator
  3. The last with one indicator, and with the A (and) condition?


getLinesWithCondition(line: string): string[] {
if (this.conditions.length === 1 && this.conditions[0].indicators.length === 0) {
return [line];
}
let lines: string[] = [];
this.conditions.forEach((condition, cIdx) => {
let i = 0;
let line = ``;
condition.indicators.forEach(ind => {
if (i >= 3) {
lines.push(line.padEnd(16));
i = 0;
}
if (i === 0) {
line = ` A${cIdx > 0 ? "O" : " "}`;
}
i++;
line += `${ind.negate ? `N` : ` `}${String(ind.indicator).padStart(2, '0')}`;
});
lines.push(line.padEnd(16));
});
lines[lines.length - 1] = lines[lines.length - 1].substring(0, 16) + line.substring(16);
return lines;
}

isActive(indicators: DisplayFileIndicators): boolean {
if (this.conditions.length <= 1 && this.conditions[0].indicators.length === 0) {
return true;
}
this.conditions.forEach(cond => {
let condResult = true;
cond.indicators.forEach(ind => {
if ((!indicators.get(ind.indicator) && !ind.negate) || (indicators.get(ind.indicator) && ind.negate)) {
condResult = false;
}
});
if (condResult) {
return true;
}
});
return false;
}

}


export class DisplayFileIndicators {
private indicators: boolean[] = Array(99).fill(false);

set(indicator: number, state: boolean) {
if (indicator < 1 || indicator > 99) {
throw new Error(`Invalid indicator number`);
}
this.indicators[indicator - 1] = state;
}

setAll(state: boolean) {
this.indicators.forEach(ind => ind = state);
}

get(indicator: number) :boolean {
if (indicator < 1 || indicator > 99) {
throw new Error(`Invalid indicator number`);
}
return this.indicators[indicator - 1];
}

}
Loading