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)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions