Skip to content

Add standard IEC 61131-3 type conversion functions (BOOL_TO_INT, etc.) #149

Description

@michaeldistel

Summary

Add first-class support for the standard IEC 61131-3 typed conversion functions (the <TYPE>_TO_<TYPE> family) across the extension: syntax highlighting, completion, hover/signature documentation, and the known-identifier set used by diagnostics.

User request

Can you guys look into adding standard conversion operators to the extension.
BOOL_TO_INT, BOOL_TO_DINT, BOOL_TO_TIME, BOOL_TO_WORD, BYTE_TO_INT, BYTE_TO_DINT, BYTE_TO_TIME, BYTE_TO_WORD, DINT_TO_BOOL, DINT_TO_BYTE, DINT_TO_INT, DINT_TO_DWORD, INT_TO_DWORD, DINT_TO_LREAL etc.

Current state

  • src/iec61131_specification.ts (standardFunctions) already lists a partial conversion set: only the BOOL / INT / DINT / REAL / STRING combinations, plus TRUNC, ROUND, CEIL, FLOOR. None of the requested combinations involving TIME, BYTE, WORD, DWORD, LREAL (and other elementary types) are present.
  • That list is consumed by src/server/providers/rename-provider.ts (blocks renaming onto a standard function name) and src/server/providers/diagnostics-provider.ts (adds them to the known-identifier set so they are not flagged as undefined). It is not wired into completion, so conversion functions do not autocomplete.
  • syntaxes/structured-text.tmLanguage.json has no rule for *_TO_* functions, so they are not highlighted as builtin functions.
  • iec61131-definitions/ contains only standard function blocks (TON, CTU, etc.); there are no entries for conversion functions, so there is no hover / signature-help / peek documentation for them.

Scope

Add the standard typed conversion functions systematically rather than ad hoc. The IEC 61131-3 pattern is <source-type>_TO_<target-type> across the elementary types:

  • Integers: SINT, USINT, INT, UINT, DINT, UDINT, LINT, ULINT
  • Bit strings: BOOL, BYTE, WORD, DWORD, LWORD
  • Reals: REAL, LREAL
  • Time/date: TIME, LTIME, DATE, TOD (TIME_OF_DAY), DT (DATE_AND_TIME)
  • Character strings: STRING, WSTRING, CHAR, WCHAR

Also cover the related standard conversions/helpers: TRUNC (already present), *_TRUNC_*, *_BCD_TO_* / *_TO_BCD_*, and the generic numeric helpers already in the list. Treat docs/IEC61131_SPECIFICATION.md (see "Type Conversion Functions") as the authority for which combinations are standard; vendor-only conversions are out of scope here (track under the vendor issues if needed).

Conversion-safety diagnostic (folded in)

Once the conversion matrix exists, classify each standard conversion by data-loss risk and surface it as a diagnostic on the explicit call site:

  • Widening / lossless (e.g. INT_TO_DINT, INT_TO_REAL, BYTE_TO_WORD): no diagnostic.
  • Narrowing / lossy (e.g. DINT_TO_INT and DINT_TO_BYTE can overflow/truncate, REAL_TO_INT truncates the fraction, LREAL_TO_REAL loses precision, DWORD_TO_BYTE drops high bits): emit a Hint / Information (faded, non-blocking) noting the potential data loss. This is informational, not an error: an explicit narrowing conversion is the IEC-recommended way to do it deliberately, so the diagnostic documents the risk rather than forbidding it.
  • The risk classification is derived from the same type model that builds the matrix (rank/width + signedness + domain), so it is data, not hand-maintained per-pair.

This is deliberately scoped to explicit *_TO_* calls only. Detecting implicit conversions (a type mismatch in an assignment or expression with no conversion function present) is a larger, separate piece of work - see the linked follow-up.

Acceptance criteria

  • The standard <TYPE>_TO_<TYPE> conversion functions are present in src/iec61131_specification.ts standardFunctions (the full standard matrix, not just the BOOL/INT/DINT/REAL/STRING subset), so diagnostics no longer flag them as undefined and rename protects them.
  • syntaxes/structured-text.tmLanguage.json highlights *_TO_* conversion functions as builtin/support functions (case-insensitive), matching how other ST tokens are scoped.
  • Conversion functions are offered in completion where standard functions are appropriate, with a clear CompletionItemKind.Function.
  • Hover / signature help shows the source and target type for a conversion function (mechanism: extend the standard-function metadata used by the hover/signature providers, or add lightweight definitions analogous to iec61131-definitions/).
  • A type model exists that records each elementary type's category, width/rank, and signedness, and drives both the legal-conversion matrix and the data-loss classification (single source of truth, no per-pair hand maintenance).
  • Narrowing/lossy explicit conversions emit a non-blocking Hint/Information diagnostic explaining the potential data loss; widening/lossless conversions emit nothing. Severity is configurable-off-able if it proves noisy.
  • Unit tests cover the new set: a representative sample of conversions is recognized (not flagged as undefined), highlighted, and completed; and the lossy-vs-lossless classification is asserted for a representative sample. Add fixtures under manual-tests/ as needed.
  • npm run test:unit and npm run webpack-prod pass.

Implementation notes

  • The single source of truth should stay src/iec61131_specification.ts; generating the matrix programmatically from a type model (a list of valid source/target pairs) is preferable to a giant hand-typed literal, to keep it maintainable.
  • Not every type pair is a legal IEC conversion; follow docs/IEC61131_SPECIFICATION.md rather than emitting the full cartesian product.
  • The data-loss classification reuses the same type model: a conversion is lossless when the target's representable domain is a superset of the source's (wider/equal width, compatible signedness, same category), and lossy otherwise. Keep this as a derived property, not a per-pair flag.

Follow-up (separate issue, not in scope here)

This issue stops at explicit conversion calls. The natural next step is full implicit type-mismatch checking: flagging an assignment or expression whose operand types differ with no conversion function present (e.g. myInt := myDint; or myReal := myInt + myReal;), and offering a quick-fix that inserts the correct <SRC>_TO_<DST> function. That needs expression-level type inference over the AST and is a meaningfully larger feature; it should be tracked separately and can build directly on the type model and matrix delivered here. See the discussion below for the bigger picture.

References

  • docs/IEC61131_SPECIFICATION.md - "Type Conversion Functions" section (authoritative list and cross-platform notes)
  • src/iec61131_specification.ts - standardFunctions (current partial list)
  • src/server/providers/diagnostics-provider.ts, src/server/providers/rename-provider.ts - current consumers
  • syntaxes/structured-text.tmLanguage.json - grammar (needs a conversion-function rule)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions