Task 6 of v0.3 plan (parser + pump class; full --live-values CLI
wiring is Task 7).
parseVarNames(text) extracts variable names from any VAR /
VAR_INPUT / VAR_OUTPUT / VAR_GLOBAL / etc. block. Handles:
- one name per declaration line
- 'AT %QX0.1' location prefix
- := initializer
- inline (* ... *) and // line comments
- multi-line (* ... *) blocks (state threaded across lines)
Doesn't handle the multi-name shorthand 'a, b : INT;' -- vanishingly
rare in practice, cost of getting it wrong is just a missing overlay.
LiveValuesPump owns a setInterval. Each tick:
- reads tui-state.json via the injected readSelection
- reads the POU's .st file from the mirror
- parseVarNames -> per-var read_variable round-trip (errors per-var
are silent, others may succeed)
- writeLiveValues snapshot
Reentrancy guard: if a tick is still in flight when the next
interval fires, skip the new tick rather than queueing. Errors at any
layer are swallowed -- pump must never crash the server.
start()/stop() lifecycle so the server can hand it to the existing
shutdown path.
57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { parseVarNames } from '../../src/live-values-pump';
|
|
|
|
describe('parseVarNames', () => {
|
|
it('extracts vars from a single VAR block', () => {
|
|
const text = [
|
|
'PROGRAM PLC_PRG',
|
|
'VAR',
|
|
' counter : INT := 0;',
|
|
' bRunning : BOOL;',
|
|
' rTemperature : REAL;',
|
|
'END_VAR',
|
|
].join('\n');
|
|
expect(parseVarNames(text)).toEqual(['counter', 'bRunning', 'rTemperature']);
|
|
});
|
|
|
|
it('handles VAR_INPUT / VAR_OUTPUT / VAR_GLOBAL too', () => {
|
|
const text = [
|
|
'FUNCTION_BLOCK FB_X',
|
|
'VAR_INPUT',
|
|
' x : INT;',
|
|
'END_VAR',
|
|
'VAR_OUTPUT',
|
|
' y : BOOL;',
|
|
'END_VAR',
|
|
'VAR',
|
|
' internal : DINT;',
|
|
'END_VAR',
|
|
].join('\n');
|
|
expect(parseVarNames(text).sort()).toEqual(['internal', 'x', 'y']);
|
|
});
|
|
|
|
it('ignores lines inside (* ... *) blocks and after //', () => {
|
|
const text = [
|
|
'VAR',
|
|
' alpha : INT;',
|
|
' (* commentedOut : BOOL; *)',
|
|
' beta : INT; // tail comment',
|
|
'END_VAR',
|
|
].join('\n');
|
|
expect(parseVarNames(text)).toEqual(['alpha', 'beta']);
|
|
});
|
|
|
|
it('returns [] when no VAR block is present', () => {
|
|
expect(parseVarNames('PROGRAM X\nEND_PROGRAM')).toEqual([]);
|
|
});
|
|
|
|
it('handles AT %X10.0 location prefix and := initializer', () => {
|
|
const text = [
|
|
'VAR',
|
|
' bRelay AT %QX0.1 : BOOL := FALSE;',
|
|
' iCount : INT := 42;',
|
|
'END_VAR',
|
|
].join('\n');
|
|
expect(parseVarNames(text)).toEqual(['bRelay', 'iCount']);
|
|
});
|
|
});
|