TapHome

Syntax and control flow

Syntax of the TapHome script language: statements and semicolons, comments, literals, IF in function and block form, SWITCH, WHILE and DO loops, BREAK, CONTINUE and RETURN.

Statements and semicolons

A script is a sequence of statements, and every statement ends with a semicolon ;. Block statements (IF … END, WHILE … LOOP, DO … LOOP WHILE …) and comments do not end with a semicolon. Keywords and names are case insensitive: IF, if and If are the same.

VAR x := 5;
IF x > 3
    x := x - 1;
END
x;
# Result: 4

The semicolon may be left out only after the last statement of the script; inside a block every statement needs it, including the last one before END or LOOP. Inside a block a missing semicolon before END or LOOP stops the script with Unexpected character 'E' at the end of statement. Expected ';' ('L' before LOOP).

Comments

A comment starts with # and runs to the end of the line. It can stand on its own line, or follow a complete statement: after its semicolon, or after END, ELSE or LOOP.

# starting value
VAR x := 5;          # a comment after the semicolon
IF x > 3
    x := 1;
END                  # end of the check

A # inside a statement (before its semicolon, or after an IF or WHILE condition) fails with Comment must start on a new line and inline comments are not supported.

Literals

A literal is a value written directly in the script.

LiteralExampleNotes
Number5, 21.5, -3Decimal point .. A number literal is a double, so 5 / 2 is 2.5. No exponent (1e3), no leading dot (.5).
Hexadecimal0xA0A0, 0xffAn int, digits not case sensitive: 0xA0A0 is 41120.
Binary0b10101010An int: 170.
BooleanTRUE, FALSE
Unknown numberNaNNever equal to anything; test it with ISNAN.
No valueNullTest it with ISNULL.
String"°C", "a\nb", "C:\\data"Escapes \n, \r, \t, \", \\, \xHH, \uXXXX. An invalid escape fails with Couldn't unescape ….
Char'A', '\n'Exactly one character.
Collection{1, 2, 3}, {"a", "b"}At least one element, see Collections.
Enum valueH, BigEndianFloat, DateTimeKind.UtcBare or with the type name, see Enum types.

IF

IF returns one of two values depending on a condition (function form), or runs one of several blocks of statements (block form).

1
2
IF(condition, valueIfTrue)
IF(condition, valueIfTrue, valueIfFalse)

Parameters

NameTypeDescription
conditionboolA non-zero number is TRUE, Null is FALSE.
valueIfTrueanyReturned when the condition is TRUE.
valueIfFalseanyOptional, returned otherwise.

Returns the selected value, or Null when the condition is not TRUE and there is no third argument. Only the selected branch is evaluated, so the other one cannot fail.

Example — safe division and a replacement for NaN. Dividing by zero stops the script with Line in script: 1 Message: Division by zero; the condition prevents it:

IF(va2 > 0, va1/va2, 0);
# Result: va1/va2, or 0 when va2 is 0
IF(ISNAN(Te), 0, Te);
# Result: 0 when the device is in error or returns NaN

Block form

1
2
3
4
5
6
7
IF condition
    statements;
ELSEIF condition
    statements;
ELSE
    statements;
END

The condition may be in parentheses and must fit on one line; the line break ends it. ELSEIF can repeat, ELSE is optional, END is mandatory. The block itself returns Null; use RETURN to produce a value from inside it.

IF Te < 5
    RETURN(1);
ELSEIF Te > 10
    RETURN(3);
ELSE
    RETURN(0);
END

Errors — Function IF requires at least 2 parameters.; Unexpected keyword 'X' at the end of IF statement. when a ; follows an inner END.

See also — SWITCH, Operators.

SWITCH

SWITCH compares a value with a list of cases and returns the result of the first matching case, or a default result when no case matches.

1
SWITCH(value, case1, result1, case2, result2, ..., defaultResult)

Remarks — SWITCH takes at least 4 and at most 100 arguments, always an even number: the value, pairs of a case and its result, and the default result. Cases are compared like =: numbers by value, text exactly; comparing text with a number fails with Operator '==' not defined …. Only the result of the matching case is evaluated.

Example — the device manual lists the active mode as bit values; the script turns them into multi-value switch positions:

SWITCH Example
SWITCH(MODBUSR(H, 168, UInt16),
    0, 0,
    0x0002, 1,
    0x0004, 2,
    0x0008, 3,
    0x0010, 4,
    0x0040, 5,
    0x0800, 6,
    NaN);

Errors — Function SWITCH requires at least 4 parameters.; Invalid arguments for SWITCH function. for an odd number of arguments.

WHILE and DO loops

WHILE repeats its statements while the condition is TRUE; DO … LOOP WHILE runs them at least once. CONTINUE; skips the rest of the pass, BREAK; leaves the loop; both are written without parentheses.

1
2
3
4
5
6
7
WHILE condition
    statements;
LOOP

DO
    statements;
LOOP WHILE condition

As with IF, the condition ends at the line break. When it starts with (, it ends at the matching ): WHILE (a > 0) AND (b > 0) takes only (a > 0) as the condition, so write WHILE (a > 0 AND b > 0).

int i := 10;
WHILE i > 0
    i := i - 1;
    IF i > 5
        CONTINUE;
    END
    BREAK;
LOOP
i;
# Result: 5
int n := 1;
DO
    n := n * 2;
LOOP WHILE n < 100
n;
# Result: 128

Errors — a loop stops with More than 1 000 000 loops, stopping loop. BREAK or CONTINUE outside a loop fails with Cannot use BREAK() outside of WHILE or DO-WHILE. A ; after an inner LOOP or END fails with Unexpected character ';' in WHILE statement.

Names are resolved before the loop keywords. A variable or a device abbreviation called Do or While hides the keyword, and the loop fails with Missing operator between 'DO' and ….

RETURN

RETURN ends the script immediately and makes the given value its result.

1
RETURN(value)

Remarks — without RETURN the result is the value of the last statement. Use RETURN to give a value from inside a block, or to stop a listener script early for messages it does not handle.

IF ISNAN(Te)
    RETURN(0);
END
Te * 1.8 + 32;
# Result: the temperature in °F, or 0 when it is unknown

See also — Script result.