-
Notifications
You must be signed in to change notification settings - Fork 91
fix(variables): allow a comma in a declaration's type so inline multi-dimensional arrays parse #1003
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
fix(variables): allow a comma in a declaration's type so inline multi-dimensional arrays parse #1003
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,3 +1,3 @@ | ||||||||||||||
| import type { LibraryState } from '../../middleware/shared/ports/library-types' | ||||||||||||||
| import { baseTypeSchema } from '../../middleware/shared/ports/plc-schemas' | ||||||||||||||
| import type { PLCDataType, PLCPou, PLCVariable } from '../../middleware/shared/ports/types' | ||||||||||||||
|
|
@@ -27,22 +27,37 @@ | |||||||||||||
| 'temp', | ||||||||||||||
| ] | ||||||||||||||
|
|
||||||||||||||
| // The type group accepts a comma so a multi-dimensional array can be declared | ||||||||||||||
| // inline: `m : ARRAY[0..1, 0..2] OF INT;`. `parseArrayType` below has always | ||||||||||||||
| // split multi-dimensional bounds, and the data-type text parser | ||||||||||||||
| // (`PLC/data-type-text-parser.ts`) already allows the comma — without it here, | ||||||||||||||
| // the only way to declare a 2D/3D array was to name an ARRAY data type first, | ||||||||||||||
| // and writing it inline failed the whole POU with "invalid or unsupported | ||||||||||||||
| // characters". | ||||||||||||||
| // | ||||||||||||||
| // The group stays lazy and is bounded by the following `AT` / `:=` / `;`, and a | ||||||||||||||
| // comma is never valid between a declaration's name and its type, so this can't | ||||||||||||||
| // swallow anything it didn't before. Note this does NOT enable multi-name | ||||||||||||||
| // declarations (`a, b : INT;`) — `name` is a single `\w+` followed by `:`. | ||||||||||||||
|
|
||||||||||||||
| // Primary format: name : type AT location := initialValue ; (* documentation *) | ||||||||||||||
| const lineRegex = | ||||||||||||||
| // eslint-disable-next-line no-useless-escape | ||||||||||||||
| /^\s*(?<name>\w+)\s*:\s*(?<type>[\w\s\[\]\.]+?)(?:\s+AT\s+(?<location>[\w\d\._%]+))?\s*(?::=\s*(?<initialValue>[^;]+?))?\s*;\s*(?:\(\*\s*(?<documentation>.*?)\s*\*\))?$/ | ||||||||||||||
| /^\s*(?<name>\w+)\s*:\s*(?<type>[\w\s\[\],\.]+?)(?:\s+AT\s+(?<location>[\w\d\._%]+))?\s*(?::=\s*(?<initialValue>[^;]+?))?\s*;\s*(?:\(\*\s*(?<documentation>.*?)\s*\*\))?$/ | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Reject commas outside inline Line 46 accepts a comma in every type expression. Restrict comma support to valid 🤖 Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Widening
Nothing rejects it — Reject empty/blank bounds — e.g. have |
||||||||||||||
|
|
||||||||||||||
| // Alternate format: name AT location : type := initialValue ; (* documentation *) | ||||||||||||||
| // This format is used by some IEC 61131-3 tools and older versions of OpenPLC Editor | ||||||||||||||
| const alternateLineRegex = | ||||||||||||||
| // eslint-disable-next-line no-useless-escape | ||||||||||||||
| /^\s*(?<name>\w+)\s+AT\s+(?<location>[\w\d\._%]+)\s*:\s*(?<type>[\w\s\[\]\.]+?)\s*(?::=\s*(?<initialValue>[^;]+?))?\s*;\s*(?:\(\*\s*(?<documentation>.*?)\s*\*\))?$/ | ||||||||||||||
| /^\s*(?<name>\w+)\s+AT\s+(?<location>[\w\d\._%]+)\s*:\s*(?<type>[\w\s\[\],\.]+?)\s*(?::=\s*(?<initialValue>[^;]+?))?\s*;\s*(?:\(\*\s*(?<documentation>.*?)\s*\*\))?$/ | ||||||||||||||
|
|
||||||||||||||
| const guessErrorReason = (line: string): string => { | ||||||||||||||
| if (!line.includes(';')) return 'missing semicolon (;) at the end of the declaration' | ||||||||||||||
| if (!line.includes(':')) return 'missing colon (:) between name and type' | ||||||||||||||
| // Comma is legal — multi-dimensional array bounds and comma-separated initial | ||||||||||||||
| // values both use it — so it must not be reported as an unsupported character. | ||||||||||||||
| // eslint-disable-next-line no-useless-escape | ||||||||||||||
| if (/[^A-Za-z0-9_\s:;=%()/*\-.\[\]]/.test(line)) return 'invalid or unsupported characters' | ||||||||||||||
| if (/[^A-Za-z0-9_\s:;=%()/*\-.,\[\]]/.test(line)) return 'invalid or unsupported characters' | ||||||||||||||
| return 'unrecognized declaration format' | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment's conclusion — "a comma is never valid between a declaration's name and its type, so this can't swallow anything it didn't before" — is only about the name side; the comma is now also accepted inside a NON-array type, where nothing validates the result.
Verified with both regexes:
x : INT, DINT;previously threw and now matches withtype = 'INT, DINT', and sincebaseTypeSchemafails and_dataTypesis unused, it becomes{definition:'user-data-type', value:'INT, DINT'}— persisted, shown in the type cell as a nonexistent type, and emitted verbatim bygetTypeAsTextasx : INT, DINT;into the generated ST (invalid ST → strucpp failure). Same forx : INT,;→value:'INT,'.The precedent cited in this very comment guards against exactly this:
data-type-text-parser.tsalso allows the comma, butbuildFieldTyperejects a non-array/non-base type that failsidentifierRegex. Mirror that guard here rather than accepting any comma-bearing string as a user data type.