Advances #165 (part of the CODESYS-on-Yocto tracker #167).
CODESYS control logic is frequently written in graphical languages (LD/FBD),
but the scanner only understood Structured-Text bodies — FBD/LD/SFC were skipped,
so their comm calls, hardcoded arguments and safety writes went unseen.
Approach
Reuse the existing "reconstruct synthetic ST → ST parser → rules" pipeline:
Input pins resolved by tracing connectionPointIn/refLocalId through the
network; LD contacts AND-chain back to the power rail; nested blocks are
referenced by a synthetic result so each call is emitted exactly once.
SFC graph is skipped, but ST/FBD/LD bodies embedded in its actions/transitions
are still translated.
Also fixes
A latent doubling bug in collect_text: roxmltree descendants() yields both
an element and its child text node, so every value was collected twice. Harmless
for ST (duplicate statements deduped) but it corrupted graphical single-token
expressions (502→502502, FALSE→FALSEFALSE). Now only text nodes are gathered.
Advances **#165** (part of the CODESYS-on-Yocto tracker **#167**).
CODESYS control logic is frequently written in **graphical languages** (LD/FBD),
but the scanner only understood Structured-Text bodies — FBD/LD/SFC were skipped,
so their comm calls, hardcoded arguments and safety writes went unseen.
## Approach
Reuse the existing "reconstruct synthetic ST → ST parser → rules" pipeline:
- **Blocks** → calls `TypeName(pin := arg, …)` (fires comm/credential/port rules).
- **Out-variables / coils** → assignments (fires credential / safety-bypass rules).
- **Input pins** resolved by tracing `connectionPointIn`/`refLocalId` through the
network; LD contacts AND-chain back to the power rail; nested blocks are
referenced by a synthetic result so each call is emitted exactly once.
- **SFC** graph is skipped, but ST/FBD/LD bodies embedded in its actions/transitions
are still translated.
## Also fixes
A latent **doubling bug** in `collect_text`: roxmltree `descendants()` yields both
an element and its child text node, so every value was collected twice. Harmless
for ST (duplicate statements deduped) but it corrupted graphical single-token
expressions (`502`→`502502`, `FALSE`→`FALSEFALSE`). Now only text nodes are gathered.
## Tests
- `pump_fbd.xml` demo fixture (Modbus block + hardcoded password + safety write).
- `fbd_graphical_body_is_analysed`, `ld_coil_and_block_translate_and_are_analysed`,
`graphical_expression_text_is_not_duplicated`.
- Full core+agent lib suites green; fmt + clippy (agent) clean.
## Follow-ons (not in this PR)
- Native `.project` / `.projectarchive` parsing + control-app library SBOM → #165 / #166
(need a real CODESYS sample to ground).
- SFC step/transition graph semantics.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
CODESYS control logic is frequently written in graphical languages, but the
scanner only understood Structured-Text bodies — FBD/LD/SFC were skipped, so
their comm calls, hardcoded arguments and safety writes went unseen.
Translate FBD/LD networks to synthetic ST and run them through the existing ST
parser + rules: blocks become calls (`TypeName(pin := arg, …)`), out-variables
and coils become assignments, and input pins are resolved by tracing
`connectionPointIn`/`refLocalId` back through the network (contacts AND-chain to
the power rail; nested blocks are referenced by a synthetic result so calls are
emitted exactly once). SFC step/transition graphs are skipped, but the ST/FBD/LD
bodies embedded in their actions/transitions are still translated.
Also fixes a latent doubling bug in `collect_text`: `descendants()` yields both
an element and its child text node, so every value was collected twice. Harmless
for ST (duplicate statements landed on one synthetic line and deduped) but it
corrupted graphical single-token expressions (`502` -> `502502`,
`FALSE` -> `FALSEFALSE`). Now only text nodes are gathered.
Adds an FBD demo fixture (pump_fbd.xml) + FBD/LD/regression tests.
Part of #165 (graphical languages). Native `.project`/`.projectarchive` parsing
and SFC graph semantics remain follow-ons. Tracker #167.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sharang
merged commit 386d8457d6 into main2026-07-16 11:43:50 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Advances #165 (part of the CODESYS-on-Yocto tracker #167).
CODESYS control logic is frequently written in graphical languages (LD/FBD),
but the scanner only understood Structured-Text bodies — FBD/LD/SFC were skipped,
so their comm calls, hardcoded arguments and safety writes went unseen.
Approach
Reuse the existing "reconstruct synthetic ST → ST parser → rules" pipeline:
TypeName(pin := arg, …)(fires comm/credential/port rules).connectionPointIn/refLocalIdthrough thenetwork; LD contacts AND-chain back to the power rail; nested blocks are
referenced by a synthetic result so each call is emitted exactly once.
are still translated.
Also fixes
A latent doubling bug in
collect_text: roxmltreedescendants()yields bothan element and its child text node, so every value was collected twice. Harmless
for ST (duplicate statements deduped) but it corrupted graphical single-token
expressions (
502→502502,FALSE→FALSEFALSE). Now only text nodes are gathered.Tests
pump_fbd.xmldemo fixture (Modbus block + hardcoded password + safety write).fbd_graphical_body_is_analysed,ld_coil_and_block_translate_and_are_analysed,graphical_expression_text_is_not_duplicated.Follow-ons (not in this PR)
.project/.projectarchiveparsing + control-app library SBOM → #165 / ONB · SBOM: control-application dependency SBOM (CODESYS libraries + runtime version) -> CVE (#166)(need a real CODESYS sample to ground).
🤖 Generated with Claude Code