Skip to content

fix(variables): allow a comma in a declaration's type so inline multi-dimensional arrays parse - #1003

Open
thiagoralves wants to merge 1 commit into
developmentfrom
fix/var-decl-multidim-array-type
Open

fix(variables): allow a comma in a declaration's type so inline multi-dimensional arrays parse#1003
thiagoralves wants to merge 1 commit into
developmentfrom
fix/var-decl-multidim-array-type

Conversation

@thiagoralves

@thiagoralves thiagoralves commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

m : ARRAY[0..1, 0..2] OF INT; written in a POU's variables text failed the whole POU, not just that line:

POU "PLC_PRG" (pous/programs/PLC_PRG.st) could not be fully parsed:
Syntax error on line 50: "m : ARRAY[0..1, 0..1] OF INT;".
Possible cause: invalid or unsupported characters.

The type capture group in generate-iec-string-to-variables.ts excluded the comma, so no line matched — and guessErrorReason, whose allowed-character set also omitted the comma, then blamed "invalid or unsupported characters". The only way to declare a 2D/3D array was to define a named ARRAY data type first and reference that.

Why the change is this small

Nothing downstream needed touching:

  • parseArrayType has always split comma-separated bounds into multiple dimensions
  • the reverse serializer emits type.value, which holds the full type string, so text → variables → text is byte-stable
  • the data-type text parser (PLC/data-type-text-parser.ts) already allowed the comma — this brings the variable parser in line with a sibling that got it right

Scope is bounded by construction

The type group stays lazy and is still bounded by the following AT / := / ;, and a comma is never valid between a declaration's name and its type. In particular this does not start accepting multi-name declarations (a, b : INT;) — the name group is a single identifier that must be followed by the colon — and a test pins that.

Tests

13 new. Inline 2D and 3D; with and without a space after the comma; of a base type and of a user-defined type; with an initial value; in the alternate located (name AT loc : type) format. Plus the negative cases: multi-name still rejected, and an unrelated syntax error no longer misreported as a bad character. And a round-trip test in the serializer's own file, since the variables table and the code view are two views of the same data.

src/frontend: 4052 passing (179 files).

Notes for the reviewer

  • The same fix is in openplc-web (autonomy-logic/openplc-web) — the two copies of this parser are byte-identical, and so are the two commits.
  • Multi-dimensional array initializers ([[1,2,3],[4,5,6]], 3D arrays) are a separate strucpp change: feat: IEC 61131-3 structure and array initialization (forum report), plus six initialization fixes STruCpp#205. This PR is what lets those types be declared inline; the two are independent but complementary.
  • Not touched: the variables-table type picker. This fixes the code-view path; whether the dropdown can construct a multi-dimensional array is a separate question.

Validated end-to-end on a real project through parse → transpile → strucpp → g++ → run, including inline 2D/3D arrays of base types, of a STRUCT, and of a function block.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Added support for inline multidimensional IEC ARRAY declarations, including spaced and unspaced dimensions.
    • Improved handling of base and custom element types, initial values, and located variables.
    • Corrected syntax error reporting for malformed declarations.
    • Preserved multidimensional array declarations during parsing and serialization.

…-dimensional arrays parse

`m : ARRAY[0..1, 0..2] OF INT;` written in a POU's variables text failed the whole
POU: the type capture group excluded the comma, so no line matched and
`guessErrorReason` — whose allowed-character set also omitted the comma — blamed
"invalid or unsupported characters". The only way to declare a 2D/3D array was to
name an ARRAY data type first and reference that.

Nothing downstream needed changing. `parseArrayType` has always split
comma-separated bounds into multiple `dimensions`, and the reverse serializer
emits `type.value`, which holds the full type string — so the round trip
(text → variables → text) is unaffected. The data-type text parser
(`PLC/data-type-text-parser.ts`) already allowed the comma; this brings the
variable parser in line with it.

Scope of the change is narrow by construction: the type group stays lazy and is
still bounded by the following `AT` / `:=` / `;`, and a comma is never valid
between a declaration's name and its type. In particular this does NOT start
accepting multi-name declarations (`a, b : INT;`) — the name group is a single
identifier that must be followed by the colon — and that stays covered by a test.

Tests: inline 2D and 3D, with and without a space after the comma, of a base and
of a user-defined type, with an initial value, in the alternate located
(`name AT loc : type`) format, plus the two negative cases — multi-name still
rejected, and an unrelated error no longer misreported as a bad character.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thiagoralves

Copy link
Copy Markdown
Contributor Author

Companion PR with the identical fix in openplc-web: Autonomy-Logic/openplc-web#662

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The IEC variable parser now accepts inline multidimensional ARRAY declarations with comma-containing type expressions. Tests cover parsing, diagnostics, and unchanged serialization through round trips.

Changes

IEC array parsing

Layer / File(s) Summary
Accept comma-containing array types
src/frontend/utils/generate-iec-string-to-variables.ts
Declaration parsing accepts inline multidimensional arrays and classifies malformed syntax errors correctly.
Validate parsing and round trips
src/frontend/utils/__tests__/generate-iec-string-to-variables.test.ts, src/frontend/utils/__tests__/generate-iec-variables-to-string.test.ts
Tests cover dimensions, element types, initial values, located variables, invalid declarations, diagnostics, and byte-stable serialization.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: joaogsp

Poem

A rabbit parsed arrays wide,
With commas neatly side by side.
Two dimensions, then three,
Round-tripped faithfully.
“No broken syntax!” it cried,
And twitched its ears with pride.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the parser fix that enables inline multidimensional array declarations.
Description check ✅ Passed The description explains the problem, implementation, scope, tests, validation, and related limitations, although it omits the template checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/var-decl-multidim-array-type

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/frontend/utils/generate-iec-string-to-variables.ts`:
- Line 46: Update the type parsing in the regex used by
generateIecStringToVariables so commas are accepted only within valid inline
ARRAY bounds; otherwise reject declarations such as value : INT, BOOL; instead
of treating them as user-defined types. Ensure parseArrayType returning null for
a comma-containing type causes the declaration to be rejected, and add a
regression test covering this input.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a7e47349-b219-4956-b119-2aee0b7ef270

📥 Commits

Reviewing files that changed from the base of the PR and between 4f05cf6 and e967a4f.

📒 Files selected for processing (3)
  • src/frontend/utils/__tests__/generate-iec-string-to-variables.test.ts
  • src/frontend/utils/__tests__/generate-iec-variables-to-string.test.ts
  • src/frontend/utils/generate-iec-string-to-variables.ts

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*\*\))?$/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject commas outside inline ARRAY bounds.

Line 46 accepts a comma in every type expression. value : INT, BOOL; now matches, fails parseArrayType, and becomes the user-defined type INT, BOOL. The serializer then emits invalid IEC text.

Restrict comma support to valid ARRAY[...] OF ... expressions, or reject a comma when parseArrayType(parsedType) returns null. Add a regression test for value : INT, BOOL;.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/frontend/utils/generate-iec-string-to-variables.ts` at line 46, Update
the type parsing in the regex used by generateIecStringToVariables so commas are
accepted only within valid inline ARRAY bounds; otherwise reject declarations
such as value : INT, BOOL; instead of treating them as user-defined types.
Ensure parseArrayType returning null for a comma-containing type causes the
declaration to be rejected, and add a regression test covering this input.

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*\*\))?$/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Widening (?<type>[\w\s\[\],\.]+?) also admits malformed bound lists, and parseArrayType's dimensionsStr.split(',') turns them into empty dimensions instead of an error. Verified by running the old and new regexes side by side:

input before after
m : ARRAY[0..1,] OF INT; throws "invalid or unsupported characters" dimensions: [{dimension:'0..1'},{dimension:''}]
m : ARRAY[,] OF INT; throws [{dimension:''},{dimension:''}]
m : ARRAY[0..1,,0..2] OF INT; throws [{dimension:'0..1'},{dimension:''},{dimension:'0..2'}]

Nothing rejects it — reconcileVariablesText writes parsed straight into pou.interface.variables, and plc-schemas.ts has no dimension schema — so it is persisted. Downstream: getTypeAsText emits ARRAY [0..1,] OF INT into the generated ST (a compile error in generated code, with no editor diagnostic), getArrayTotalElements returns 0 (the Python-extension struct becomes uint8_t m[0]; and the copy loops become no-ops), and opening/saving the array modal silently drops the empty entry, converting the 2D array to 1D.

Reject empty/blank bounds — e.g. have parseArrayType return null when any dimensionParts entry is empty (the GUI already refuses this via arrayValidation) — and add negative tests for the trailing and doubled comma.

// 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

Copy link
Copy Markdown
Contributor

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 with type = 'INT, DINT', and since baseTypeSchema fails and _dataTypes is unused, it becomes {definition:'user-data-type', value:'INT, DINT'} — persisted, shown in the type cell as a nonexistent type, and emitted verbatim by getTypeAsText as x : INT, DINT; into the generated ST (invalid ST → strucpp failure). Same for x : INT,;value:'INT,'.

The precedent cited in this very comment guards against exactly this: data-type-text-parser.ts also allows the comma, but buildFieldType rejects a non-array/non-base type that fails identifierRegex. Mirror that guard here rather than accepting any comma-bearing string as a user data type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants