S7 Lint for VS Code is an extension for static analysis and editor support for Siemens TIA Portal source and export formats.
This is an independent open-source project. It is not an official Siemens product and is not affiliated with, endorsed by, sponsored by, or maintained by Siemens AG. Siemens, SIMATIC, TIA Portal, and other product names are trademarks of their respective owners.
The extension is currently version 0.1.5 and under active development. It is
intended to catch common structural, type, symbol, and instruction-call errors
before code is imported or compiled in TIA Portal. It is not a replacement for
the target CPU and TIA Portal compiler.
Supported files
.scl: authored SCL files containing one or more block or type declarations..s7dcl: LAD/FBD declaration exports, program blocks, andTYPEdeclarations..udt: text-format PLC data type declarations.**/*.xml: TIA XML exports, anywhere in the workspace. PLC data type exports feed the workspace type cache; DATA_BLOCK exports (SW.Blocks.InstanceDB/GlobalDB) feed the block index, so references to an instance DB resolve even though TIA writes it in a different format from the FUNCTION_BLOCK it instances. Every file is offered to both parsers -- they key off different root elements -- because export layout does not reliably separate the two..s7res: multilingual resources used by definition, rename, and inline-hint support.
Current capabilities
Diagnostics
- Validates LAD/FBD and SCL instruction names, pins or parameters, call shape,
language availability, templates, results, and selected memory-area rules
against the registries under
resources/. - Checks LAD/FBD rung connectivity back to
wire#powerrail. - Checks SCL syntax structure, undeclared identifiers, illegal member access, condition types, expression types, conversions, loop constraints, and instruction-result usage.
- Checks literals and resolvable operands against declared or expected types.
- Accepts the two spellings TIA Portal's own external-source importer accepts:
a local reference written without its
#(IF Active THEN,SecondTick(IN := ..., PT := ...)) when the block declares that name, and any casing of a type name (BYTEandByteare one type). Both are checked exactly like their#-prefixed / canonically-cased equivalents — a bare word the block does NOT declare is still an error. - Builds a workspace type cache for UDT dependencies, duplicate declarations, circular references, array bounds, and nesting limits.
- Applies declaration-section, reference, pointer, array, and selected cross-parameter rules where the required context is available.
The parser and checks are deliberately conservative: when a type, target, or expression cannot be resolved confidently, the extension avoids guessing.
Editor support
- Context-aware completion for declarations, types, instructions, symbols, and
top-level block templates, including dotted member completion on instance
DATA_BLOCKs and quoted external block references. Datatype completion also
works after
:inside inline, UDT, and DATA_BLOCKSTRUCT ... END_STRUCTdeclarations, with or without whitespace around the colon. - Dotted member completion off a local tag, written
#tag.or baretag., resolving through workspace FUNCTION_BLOCK/DATA_BLOCK interfaces, UDT fields, system-struct fields (IEC_TIMER,ErrorStruct, …), inlineSTRUCT … END_STRUCTfields, and instruction-instance pins — chained to any depth across all five, and using SCL's own parameter casing in.scl(#edge.CLK/edge.Q, not the graphicalclk/q). - Hover, definition, rename, and semantic-token providers, including instance
DATA_BLOCK hovers that resolve to their instruction or FUNCTION_BLOCK type.
Workspace UDT declarations and their case-insensitive references can be
renamed directly from the type name.
Highlighting uses standard VS Code semantic families, so the user's active
dark or light theme controls every colour. S7-specific semantic subtypes
retain normal-theme fallbacks while allowing independent styling. The six
elementary families (
s7TemporalType,s7IntegerType,s7BooleanType,s7FloatType,s7GenericType, ands7TextType) inherittype;s7UdtTypeinheritsstruct,s7CallableTypeinheritsclass, ands7CallableInstanceands7DataBlockinheritvariable, whiles7InterfaceMemberinheritsparameter. Direct call expressions remainfunction; plain/UDT-backed DATA_BLOCK storage usess7DataBlock, while an FB/instruction instance DB usess7CallableInstance. Fields/interface values areproperty/parameter; a resolved scalar field below an FB/FC Input, Output, or InOut path is ans7InterfaceMember, preserving the theme's parameter color through nested UDT access while containers and indexable segments keep their structural colors. No S7-specific colour theme is required. Two composable capability modifiers refine value occurrences without replacing those roles:s7Containermeans the value exposes structured members through dotted access, ands7Indexablemeans it supports[...](Array,String, orWString). AnARRAY OFa UDT/STRUCT carries both; a scalar leaf carries neither. The automatic palette gives container, indexable, and combined members related but distinct colours, while root objects such as DATA_BLOCKs and callable instances keep their identity colour. Keyword-family tokens are split the way most language grammars split them, rather than sharing one colour: control flow (IF/END_IF/RETURN/…), type constructors (STRUCT/END_STRUCTand genericARRAY/OF/REF_TO), logical operators (NOT/AND/OR/XOR/MOD), and language constants (TRUE/FALSE,NULL/ZERO). A pragma value is attribute data, not program data, so'TRUE'in{ S7_Optimized_Access := 'TRUE' }reads as the string it is rather than as the boolean constant. - Type names are classified by what the type means for the thing being
declared, identically at a declaration and at every reference. Elementary
types are grouped as temporal (
Time,Date,DTL, …), integer/bit (Int,UInt,Byte,Word, …), boolean (Bool), floating point (Real,LReal), generic/reference (Void,Variant,Any,Pointer,REF_TO,ARRAY/OF), and text (String,WString,Char,WChar). A Siemens record (IEC_TIMER) remainsstruct.defaultLibrary, a project PLC data type ("KDT_Header") ass7UdtType, and an FB/instruction instance type ("FB_Pump",TON) ass7CallableType. The declared instance iss7CallableInstance, becomingfunctiononly at a direct call site — soPump : "FB_Pump";andPump(...)read like object construction and invocation in other languages. A global DATA_BLOCK such as"DB_IPC_Comms"iss7DataBlockat its declaration and every reference, making global structured storage visually distinct from local variables. Composite declarations stay readable through theARRAY/OF/STRUCTkeywords themselves. A FUNCTION's return type is coloured on the same scheme (it previously had no colour at all). Bare,#-less local references and unquoted workspace-block calls resolve for hover, Ctrl+click, and rename exactly like their prefixed/quoted equivalents. - Hovering a PLC data type or global DATA_BLOCK shows its calculated Siemens
standard/non-optimized storage size and included padding. Hovering an
individual declaration name in a UDT
STRUCT, DATA_BLOCKVAR, or inlineSTRUCTadditionally shows that member's size and container-relative byte offset; packedBOOLmembers usebyte.bitnotation. Arrays, sizedString/WString, nested structures, and referenced UDTs participate in the calculation. If a dependency has no known storage size, the hover lists each unresolved member path instead of presenting a guessed total or offset. - Distinct colors for the S7 datatype and object/callable subtypes activate automatically
when a supported SCL/declaration/UDT editor becomes active. The preset is
scoped to the current dark/light theme in User Settings, preserves unrelated
rules, and upgrades recognized older S7 Lint values without overwriting a
manually customized S7 selector. High-contrast themes are left unchanged.
Run S7 Lint: Disable Recommended Semantic Colors (or turn off
tiaLint.recommendedSemanticColors.enabled) to remove managed preset rules; Install Recommended Semantic Colors re-enables/restores the preset. - Definition and rename support for
.s7resmultilingual resources. - Quick fixes for explicit expression conversions and instruction/FUNCTION_BLOCK instances, including auto-creating a single-instance DATA_BLOCK when completing a member on a bare FUNCTION_BLOCK type.
- Quick fixes that repair the instruction registry itself, for the two
diagnostics usually caused by a gap or a transcription slip in the YAML
rather than by the checked source: marking a pin optional
(
missing-required-pin) and scaffolding a missing entry from its call site (unknown-instruction). Both reload the rule set and re-lint immediately, and can open the registry editor directly on the affected entry. - Inline multilingual-text hints with configurable locale fallback.
- A visual Instruction Registry Editor (
S7 Lint: Open Instruction Registry Editor) for creating, editing, moving, and deleting instruction and system-type entries across the registry's YAML files, with schema-driven validation, drag-and-drop reordering, undo/redo, and comment/formatting- preserving atomic saves. Saving reloads the rule set and re-lints open files in place, so an edited entry takes effect without reloading the window.
Knowledge bases
The YAML under resources/ is hand-maintained source data and is loaded
directly at runtime:
instruction-registry/: LAD/FBD and SCL instruction signatures.type-registry/: base types, system types, expression domains, composition rules, and declaration constraints.diagnostic-registry/: diagnostic codes, severities, and message templates.system-registry/: shared memory-area and instruction-result schemas.
There is no generated mirror or synchronization step for these registries.
Repository layout
./
src/ extension, parsers, analysis, providers, linters
resources/ runtime YAML registries
docs/fbd-knowhow/ LAD/FBD syntax and fixture-derived notes
docs/source-document-format/ independent source-format interoperability notes
scripts/ test runners and stable fixtures
syntaxes/ VS Code language grammar and configuration
themes/ bundled VS Code theme
Build and test
Run commands from the repository root:
npm install
npm test
npm test compiles the extension and runs all regression suites:
| Command | Scope |
|---|---|
npm run test:semantic-colors |
automatic palette installation and migration |
npm run test:completion |
completion and context classification |
npm run test:rename |
UDT and symbol rename behavior |
npm run test:quickfix |
instance-generation quick fixes |
npm run test:manifest |
manifest-driven parser and semantic diagnostics |
npm run test:annotated |
exact line-annotated expression diagnostics |
npm run test:instance-context |
instance-type context legality (VAR sections, call shapes) |
npm run test:editor |
instruction registry editor's YAML document model |
npm run test:editor-service |
instruction registry editor's service/workspace layer |
npm run test:smoke |
anonymized SCL and graphical-control fixtures |
The diagnostic fixtures and their assertion contracts are documented in
scripts/fixtures/scl-diagnostics/.
Press F5 in VS Code with this directory open to launch an Extension Development Host. The launch configuration compiles and bundles the extension first.
Package a VSIX
npm run bundle
npx @vscode/vsce package
Commands and settings
The extension contributes these commands:
- S7 Lint: Rebuild Type Cache
- S7 Lint: Re-lint All Open Files
- S7 Lint: Show Loaded Rule Stats
- S7 Lint: Open Instruction Registry Editor
- S7 Lint: Install Recommended Semantic Colors
- S7 Lint: Disable Recommended Semantic Colors
Two further commands back the registry quick fixes
(tiaLint.registryMarkPinOptional, tiaLint.registryScaffoldInstruction).
They take arguments supplied by the diagnostic, so they are hidden from the
command palette and are invoked from the lightbulb only.
tiaLint.mlcLocale selects the preferred locale for multilingual resource
resolution. Resolution falls back to en-US and then to an available locale.
tiaLint.recommendedSemanticColors.enabled controls automatic installation of
the theme-scoped S7 semantic palette. Disabling it removes only values managed
by S7 Lint and preserves unrelated or manually customized semantic colors.
Known limitations
- Target CPU family and firmware are not project configuration inputs yet.
platform-availability.NOTLOADED.yamlis reference data and is intentionally not loaded. - A block's "IEC check" property is not visible in any export, so rules it
toggles cannot be enforced by target. Where the two readings conflict, the
permissive one is used, because reporting a hard error on code that compiles
leaves the author nothing to act on. Bit-string arithmetic is the current
example (see
expression-operators.yaml). - A FUNCTION's declared return type is not parsed, so assignments to its result variable are recognised but not type-checked.
- Type checks skip unresolved symbols and expression shapes for which a safe, single result type cannot be inferred.
- A
+or-written with no space before a digit is lexed as part of the number, so unspaced arithmetic (4-1) has no operator token left to parse and is reported as a missing semicolon. Spaced (4 - 1) parses correctly. - XML UDT parsing has no per-member source positions, so XML cache diagnostics are reported on line 1.
- The workspace type and block caches rebuild in full after relevant file changes rather than incrementally.
shape-onlyregistry entries provide useful call-shape validation but do not justify the same hard-error confidence asconfirmed-compiledentries.
Source-format scope and attribution are documented separately in
docs/source-document-format/.
License
Licensed under the Apache License 2.0.