Skip to content

Commit 60fd3c0

Browse files
committed
update validation
1 parent 36cadc3 commit 60fd3c0

File tree

1 file changed

+155
-67
lines changed

1 file changed

+155
-67
lines changed

src/features/dfdElements/outputPortBehaviorValidation.ts

+155-67
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,42 @@ interface PortBehaviorValidationError {
2020
*/
2121
@injectable()
2222
export class PortBehaviorValidator {
23-
// Regex that validates assignments
24-
// Matches "Assignment({input_Pins};TERM_REGEX;{out_Label})"
25-
private static readonly ASSIGNMENT_REGEX =
26-
/^Assignment\(\{(([A-Za-z0-9_][A-Za-z0-9_\|]+(,\s*[A-Za-z0-9_\|]+)*)?)\};(\s*|!|TRUE|FALSE|\|\||&&|\(|\)|([A-Za-z0-9_]*\.[A-Za-z0-9_]*))+;\{(((([A-Za-z0-9_]+)\.[A-Za-z0-9_]+)+(,\s*([A-Za-z0-9_]+\.[A-Za-z0-9_]+))*)?)\}\)+$/;
23+
private static readonly INPUT_LABEL_REGEX = /[A-Za-z0-9_][A-Za-z0-9_\|]+/;
2724

28-
// Regex that validates forwarding
29-
// Matches "Forwarding({input_pins})"
30-
private static readonly FORWARDING_REGEX =
31-
/^Forwarding\(\{[A-Za-z0-9_][A-Za-z0-9_\|]+(,\s*[A-Za-z0-9_][A-Za-z0-9_\|]+)*\}\)$/;
25+
private static readonly OUTPUT_LABEL_REGEX = /[A-Za-z0-9_]+\.[A-Za-z0-9_]+/;
26+
27+
private static readonly LABEL_REGEX = /([A-Za-z0-9_]+)\.([A-Za-z0-9_]+)/g;
3228

3329
// Regex that validates a term
3430
// Has the label type and label value that should be set as capturing groups.
3531
private static readonly TERM_REGEX =
36-
/^(\s*|!|TRUE|FALSE|\|\||&&|\(|\)|([A-Za-z0-9_]+\.[A-Za-z0-9_]+(?![A-Za-z0-9_]*\.[A-Za-z0-9_]*)))+$/g;
32+
/(?:\s*|!|TRUE|FALSE|\|\||&&|\(|\)|(?:[A-Za-z0-9_]+\.[A-Za-z0-9_]+(?![A-Za-z0-9_]*\.[A-Za-z0-9_]*)))+/g;
3733

38-
private static readonly LABEL_REGEX = /([A-Za-z0-9_]+)\.([A-Za-z0-9_]+)/g;
34+
// Regex that validates assignments
35+
// Matches "Assignment({input_Pins};TERM_REGEX;{out_Label})"
36+
private static readonly ASSIGNMENT_REGEX = new RegExp(
37+
"^assign (" +
38+
PortBehaviorValidator.BUILD_COMMA_SEPARATED_LIST_REGEX(PortBehaviorValidator.OUTPUT_LABEL_REGEX).source +
39+
") if (" +
40+
PortBehaviorValidator.TERM_REGEX.source +
41+
")(?: from (" +
42+
PortBehaviorValidator.BUILD_COMMA_SEPARATED_LIST_REGEX(PortBehaviorValidator.INPUT_LABEL_REGEX).source +
43+
"))?$",
44+
);
45+
46+
// Regex that validates forwarding
47+
// Matches "forward input_pins" where input_pins is a comma separated list of input pins.
48+
private static readonly FORWARDING_REGEX = new RegExp(
49+
"^forward " +
50+
PortBehaviorValidator.BUILD_COMMA_SEPARATED_LIST_REGEX(PortBehaviorValidator.INPUT_LABEL_REGEX).source +
51+
"$",
52+
);
53+
54+
private static readonly SET_AND_UNSET_REGEX = new RegExp(
55+
"^(un)?set " +
56+
PortBehaviorValidator.BUILD_COMMA_SEPARATED_LIST_REGEX(PortBehaviorValidator.OUTPUT_LABEL_REGEX).source +
57+
"$",
58+
);
3959

4060
// Regex matching alphanumeric characters.
4161
public static readonly REGEX_ALPHANUMERIC = /[A-Za-z0-9_\|]+/;
@@ -83,12 +103,16 @@ export class PortBehaviorValidator {
83103
return;
84104
}
85105

86-
if (line.startsWith("Forwarding")) {
106+
if (line.startsWith("forward")) {
87107
return this.validateForwardStatement(line, lineNumber, port);
88108
}
89109

90-
if (line.startsWith("Assignment")) {
91-
return this.validateSetStatement(line, lineNumber, port);
110+
if (line.startsWith("set") || line.startsWith("unset")) {
111+
return this.validateSetAndUnsetStatement(line, lineNumber);
112+
}
113+
114+
if (line.startsWith("assign")) {
115+
return this.validateAssignStatement(line, lineNumber, port);
92116
}
93117

94118
return [
@@ -109,12 +133,12 @@ export class PortBehaviorValidator {
109133
return [
110134
{
111135
line: lineNumber,
112-
message: "invalid forwarding(Template:Forwarding({in_ports})",
136+
message: "invalid forwarding(Template: forward <i>input_pins</i>)",
113137
},
114138
];
115139
}
116140

117-
const inputsString = line.substring("Forwarding({".length, line.length - 2);
141+
const inputsString = line.substring("forward ".length);
118142
const inputs = inputsString.split(",").map((input) => input.trim());
119143
if (inputs.filter((input) => input !== "").length === 0) {
120144
return [
@@ -211,68 +235,137 @@ export class PortBehaviorValidator {
211235
return undefined;
212236
}
213237

214-
private validateSetStatement(
215-
line: string,
216-
lineNumber: number,
217-
port: DfdOutputPortImpl,
218-
): PortBehaviorValidationError[] | undefined {
219-
const match = line.match(PortBehaviorValidator.ASSIGNMENT_REGEX);
238+
private validateSetAndUnsetStatement(line: string, lineNumber: number): PortBehaviorValidationError[] | undefined {
239+
const match = line.match(PortBehaviorValidator.SET_AND_UNSET_REGEX);
220240
if (!match) {
221241
return [
222242
{
223243
line: lineNumber,
224-
message: "invalid assignment(Template:Assignment({in_ports}; term; {out_label})",
244+
message:
245+
"invalid assignment(Template:" +
246+
(line.startsWith("set") ? "set" : "unset") +
247+
" <i>out_labels</i>)",
225248
},
226249
];
227250
}
228251

229-
// Parenthesis must be balanced.
230-
let parenthesisLevel = 0;
231-
for (let strIdx = 0; strIdx < line.length; strIdx++) {
232-
const char = line[strIdx];
233-
if (char === "(") {
234-
parenthesisLevel++;
235-
} else if (char === ")") {
236-
parenthesisLevel--;
252+
const inputAccessErrors = [];
253+
254+
const outLabel = line
255+
.substring((line.startsWith("set") ? "set" : "unset").length + 1)
256+
.trim()
257+
.split(",")
258+
.map((variable) => variable.trim());
259+
260+
for (const typeValuePair of outLabel) {
261+
if (typeValuePair === "") continue;
262+
263+
const inputLabelType = typeValuePair.split(".")[0].trim();
264+
const inputLabelTypeObject = this.labelTypeRegistry
265+
?.getLabelTypes()
266+
.find((type) => type.name === inputLabelType);
267+
if (!inputLabelTypeObject) {
268+
let idx = line.indexOf(inputLabelType);
269+
while (idx !== -1) {
270+
// Check that this is not a substring of another label type.
271+
if (
272+
// must start after a dot and end before a dot
273+
line[idx - 1] === "." &&
274+
line[idx + inputLabelType.length] === "."
275+
) {
276+
inputAccessErrors.push({
277+
line: lineNumber,
278+
message: `unknown label type: ${inputLabelType}`,
279+
colStart: idx,
280+
colEnd: idx + inputLabelType.length,
281+
});
282+
}
283+
284+
idx = line.indexOf(inputLabelType, idx + 1);
285+
}
286+
}
287+
288+
if (typeValuePair.indexOf(".") !== -1) {
289+
if (typeValuePair.split(".")[1] === null || typeValuePair.split(".")[1] === "") continue;
290+
const inputLabelValue = typeValuePair.split(".")[1].trim();
291+
292+
const inputLabelTypeObject = this.labelTypeRegistry
293+
?.getLabelTypes()
294+
.find((type) => type.name === inputLabelType);
295+
if (!inputLabelTypeObject) {
296+
let idx = line.indexOf(inputLabelType);
297+
while (idx !== -1) {
298+
// Check that this is not a substring of another label type.
299+
if (
300+
// must start after a dot and end before a dot
301+
line[idx - 1] === "." &&
302+
line[idx + inputLabelType.length] === "."
303+
) {
304+
inputAccessErrors.push({
305+
line: lineNumber,
306+
message: `unknown label type: ${inputLabelType}`,
307+
colStart: idx,
308+
colEnd: idx + inputLabelType.length,
309+
});
310+
}
311+
312+
idx = line.indexOf(inputLabelType, idx + 1);
313+
}
314+
} else if (!inputLabelTypeObject.values.find((value) => value.text === inputLabelValue)) {
315+
let idx = line.indexOf(inputLabelValue);
316+
while (idx !== -1) {
317+
// Check that this is not a substring of another label value.
318+
if (
319+
// must start after a dot and end at the end of the alphanumeric text
320+
line[idx - 1] === "." &&
321+
// Might be at the end of the line
322+
(!line[idx + inputLabelValue.length] ||
323+
!line[idx + inputLabelValue.length].match(PortBehaviorValidator.REGEX_ALPHANUMERIC))
324+
) {
325+
inputAccessErrors.push({
326+
line: lineNumber,
327+
message: `unknown label value of label type ${inputLabelType}: ${inputLabelValue}`,
328+
colStart: idx,
329+
colEnd: idx + inputLabelValue.length,
330+
});
331+
}
332+
333+
idx = line.indexOf(inputLabelValue, idx + 1);
334+
}
335+
}
237336
}
238337

239-
if (parenthesisLevel < 0) {
240-
return [
241-
{
242-
line: lineNumber,
243-
message: "invalid assignment: missing opening parenthesis",
244-
colStart: strIdx,
245-
colEnd: strIdx + 1,
246-
},
247-
];
338+
if (typeValuePair.split(".")[2] !== undefined) {
339+
inputAccessErrors.push({
340+
line: lineNumber,
341+
message: `invalid label definition`,
342+
});
248343
}
249344
}
250345

251-
if (parenthesisLevel !== 0) {
346+
return inputAccessErrors.length > 0 ? inputAccessErrors : [];
347+
}
348+
349+
private validateAssignStatement(
350+
line: string,
351+
lineNumber: number,
352+
port: DfdOutputPortImpl,
353+
): PortBehaviorValidationError[] | undefined {
354+
const match = line.match(PortBehaviorValidator.ASSIGNMENT_REGEX);
355+
if (!match) {
252356
return [
253357
{
254358
line: lineNumber,
255-
message: "invalid assignment: missing closing parenthesis",
359+
message: "invalid assignment(Template:assign out_labels if term from in_pins)",
256360
},
257361
];
258362
}
259363

260364
// Extract all used inputs, label types and the corresponding label values.
261-
var term = line.split(";")[1].trim(); // get everything after the ;
262-
if (term.length === 0) {
263-
return [
264-
{
265-
line: lineNumber,
266-
message: "invalid assignment: missing term",
267-
},
268-
];
269-
}
270-
if (term.indexOf(";") !== -1) {
271-
term = term.split(";")[0];
272-
}
365+
let term = match[2];
273366

274367
const termMatch = term.match(PortBehaviorValidator.TERM_REGEX);
275-
if (!termMatch) {
368+
if (term == "" || !termMatch) {
276369
return [
277370
{
278371
line: lineNumber,
@@ -284,6 +377,8 @@ export class PortBehaviorValidator {
284377
const matches = [...term.matchAll(PortBehaviorValidator.LABEL_REGEX)];
285378
const inputAccessErrors = [];
286379

380+
console.log(matches);
381+
287382
for (const inputMatch of matches) {
288383
const inputLabelType = inputMatch[1];
289384
const inputLabelValue = inputMatch[2];
@@ -353,19 +448,8 @@ export class PortBehaviorValidator {
353448
}
354449
const availableInputs = node.getAvailableInputs();
355450

356-
const innerContent = line.substring("Assignment(".length, line.length - 1);
357-
358-
// Step 2: Split by the semicolons to separate the blocks
359-
const parts = innerContent.split(";").map((part) => part.trim());
360-
361-
const inPorts = parts[0]
362-
.substring(1, parts[0].length - 1)
363-
.split(",")
364-
.map((variable) => variable.trim());
365-
const outLabel = parts[2]
366-
.substring(1, parts[2].length - 1)
367-
.split(",")
368-
.map((variable) => variable.trim());
451+
const outLabel = match[1].split(",").map((variable) => variable.trim());
452+
const inPorts = match[3] ? match[3].split(",").map((variable) => variable.trim()) : [];
369453

370454
// Check for each input access that the input exists and that the label type and value are valid.
371455

@@ -472,4 +556,8 @@ export class PortBehaviorValidator {
472556

473557
return inputAccessErrors.length > 0 ? inputAccessErrors : [];
474558
}
559+
560+
private static BUILD_COMMA_SEPARATED_LIST_REGEX(regex: RegExp): RegExp {
561+
return new RegExp(regex.source + "(?:, " + regex.source + ")*");
562+
}
475563
}

0 commit comments

Comments
 (0)