@@ -20,22 +20,42 @@ interface PortBehaviorValidationError {
20
20
*/
21
21
@injectable ( )
22
22
export class PortBehaviorValidator {
23
- // Regex that validates assignments
24
- // Matches "Assignment({input_Pins};TERM_REGEX;{out_Label})"
25
- private static readonly ASSIGNMENT_REGEX =
26
- / ^ A s s i g n m e n t \( \{ ( ( [ A - Z a - z 0 - 9 _ ] [ A - Z a - z 0 - 9 _ \| ] + ( , \s * [ A - Z a - z 0 - 9 _ \| ] + ) * ) ? ) \} ; ( \s * | ! | T R U E | F A L S E | \| \| | & & | \( | \) | ( [ A - Z a - z 0 - 9 _ ] * \. [ A - Z a - z 0 - 9 _ ] * ) ) + ; \{ ( ( ( ( [ A - Z a - z 0 - 9 _ ] + ) \. [ A - Z a - z 0 - 9 _ ] + ) + ( , \s * ( [ A - Z a - z 0 - 9 _ ] + \. [ A - Z a - z 0 - 9 _ ] + ) ) * ) ? ) \} \) + $ / ;
23
+ private static readonly INPUT_LABEL_REGEX = / [ A - Z a - z 0 - 9 _ ] [ A - Z a - z 0 - 9 _ \| ] + / ;
27
24
28
- // Regex that validates forwarding
29
- // Matches "Forwarding({input_pins})"
30
- private static readonly FORWARDING_REGEX =
31
- / ^ F o r w a r d i n g \( \{ [ A - Z a - z 0 - 9 _ ] [ A - Z a - z 0 - 9 _ \| ] + ( , \s * [ A - Z a - z 0 - 9 _ ] [ A - Z a - z 0 - 9 _ \| ] + ) * \} \) $ / ;
25
+ private static readonly OUTPUT_LABEL_REGEX = / [ A - Z a - z 0 - 9 _ ] + \. [ A - Z a - z 0 - 9 _ ] + / ;
26
+
27
+ private static readonly LABEL_REGEX = / ( [ A - Z a - z 0 - 9 _ ] + ) \. ( [ A - Z a - z 0 - 9 _ ] + ) / g;
32
28
33
29
// Regex that validates a term
34
30
// Has the label type and label value that should be set as capturing groups.
35
31
private static readonly TERM_REGEX =
36
- / ^ ( \s * | ! | T R U E | F A L S E | \| \| | & & | \( | \) | ( [ A - Z a - z 0 - 9 _ ] + \. [ A - Z a - z 0 - 9 _ ] + (? ! [ A - Z a - z 0 - 9 _ ] * \. [ A - Z a - z 0 - 9 _ ] * ) ) ) + $ / g;
32
+ / (?: \s * | ! | T R U E | F A L S E | \| \| | & & | \( | \) | (?: [ A - Z a - z 0 - 9 _ ] + \. [ A - Z a - z 0 - 9 _ ] + (? ! [ A - Z a - z 0 - 9 _ ] * \. [ A - Z a - z 0 - 9 _ ] * ) ) ) + / g;
37
33
38
- private static readonly LABEL_REGEX = / ( [ A - Z a - z 0 - 9 _ ] + ) \. ( [ A - Z a - z 0 - 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
+ ) ;
39
59
40
60
// Regex matching alphanumeric characters.
41
61
public static readonly REGEX_ALPHANUMERIC = / [ A - Z a - z 0 - 9 _ \| ] + / ;
@@ -83,12 +103,16 @@ export class PortBehaviorValidator {
83
103
return ;
84
104
}
85
105
86
- if ( line . startsWith ( "Forwarding " ) ) {
106
+ if ( line . startsWith ( "forward " ) ) {
87
107
return this . validateForwardStatement ( line , lineNumber , port ) ;
88
108
}
89
109
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 ) ;
92
116
}
93
117
94
118
return [
@@ -109,12 +133,12 @@ export class PortBehaviorValidator {
109
133
return [
110
134
{
111
135
line : lineNumber ,
112
- message : "invalid forwarding(Template:Forwarding({in_ports} )" ,
136
+ message : "invalid forwarding(Template: forward <i>input_pins</i> )" ,
113
137
} ,
114
138
] ;
115
139
}
116
140
117
- const inputsString = line . substring ( "Forwarding({ " . length , line . length - 2 ) ;
141
+ const inputsString = line . substring ( "forward " . length ) ;
118
142
const inputs = inputsString . split ( "," ) . map ( ( input ) => input . trim ( ) ) ;
119
143
if ( inputs . filter ( ( input ) => input !== "" ) . length === 0 ) {
120
144
return [
@@ -211,68 +235,137 @@ export class PortBehaviorValidator {
211
235
return undefined ;
212
236
}
213
237
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 ) ;
220
240
if ( ! match ) {
221
241
return [
222
242
{
223
243
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>)" ,
225
248
} ,
226
249
] ;
227
250
}
228
251
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
+ }
237
336
}
238
337
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
+ } ) ;
248
343
}
249
344
}
250
345
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 ) {
252
356
return [
253
357
{
254
358
line : lineNumber ,
255
- message : "invalid assignment: missing closing parenthesis " ,
359
+ message : "invalid assignment(Template:assign out_labels if term from in_pins) " ,
256
360
} ,
257
361
] ;
258
362
}
259
363
260
364
// 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 ] ;
273
366
274
367
const termMatch = term . match ( PortBehaviorValidator . TERM_REGEX ) ;
275
- if ( ! termMatch ) {
368
+ if ( term == "" || ! termMatch ) {
276
369
return [
277
370
{
278
371
line : lineNumber ,
@@ -284,6 +377,8 @@ export class PortBehaviorValidator {
284
377
const matches = [ ...term . matchAll ( PortBehaviorValidator . LABEL_REGEX ) ] ;
285
378
const inputAccessErrors = [ ] ;
286
379
380
+ console . log ( matches ) ;
381
+
287
382
for ( const inputMatch of matches ) {
288
383
const inputLabelType = inputMatch [ 1 ] ;
289
384
const inputLabelValue = inputMatch [ 2 ] ;
@@ -353,19 +448,8 @@ export class PortBehaviorValidator {
353
448
}
354
449
const availableInputs = node . getAvailableInputs ( ) ;
355
450
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 ( ) ) : [ ] ;
369
453
370
454
// Check for each input access that the input exists and that the label type and value are valid.
371
455
@@ -472,4 +556,8 @@ export class PortBehaviorValidator {
472
556
473
557
return inputAccessErrors . length > 0 ? inputAccessErrors : [ ] ;
474
558
}
559
+
560
+ private static BUILD_COMMA_SEPARATED_LIST_REGEX ( regex : RegExp ) : RegExp {
561
+ return new RegExp ( regex . source + "(?:, " + regex . source + ")*" ) ;
562
+ }
475
563
}
0 commit comments