Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions book/src/libraries/external_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,58 @@ At compilation time, the function `log` will be defined as an externally availab

> Note: At linking time, a `log` function with a compatible signature must be available on the system.

## Generic Functions

A `FUNCTION` can be made generic by declaring one or more type parameters with a
type-nature constraint, e.g. `<T: ANY_INT>`. The type parameters may be used as the type
of inputs, outputs and the return value:

```iecst
FUNCTION MAX <T: ANY_ELEMENTARY> : T
VAR_INPUT
in1 : T;
in2 : T;
END_VAR
END_FUNCTION
```

A generic function is never called directly. Every call is resolved to a concrete
*monomorphization* whose name is the generic function's name followed by `__<TYPE>` for
the resolved type argument. For example, `MAX(aDint, bDint)` resolves to `MAX__DINT`.

The compiler does not synthesize the body of a monomorphization; each one must be
*provided*, as one of:

- an ordinary `FUNCTION` with the mangled name (an ST body),
- an `{external}` declaration of the mangled name (implemented elsewhere, e.g. in C or
Rust, resolved at link time), or
- a compiler builtin.

Calling a generic with a type for which no monomorphization is provided is reported as an
unresolved reference (`E048`).

### Monomorphizations returning aggregate types

When a generic function returns an aggregate type (`STRING`, `WSTRING`, an array or a
struct), its monomorphization must be **declared in `ST`** — either as a body or as an
`{external}` declaration. A symbol that exists only at link time (with no `ST`
declaration) is enough for a scalar return, but not for an aggregate return: an
aggregate-returning generic call whose monomorphization is not declared is reported as
`E048` at compile time rather than failing at link time or run time.

For example, the standard `TO_STRING <T: ANY> : STRING` conversion declares a
monomorphization for every supported source type (`TO_STRING__DINT`, `TO_STRING__REAL`,
…). Calling `TO_STRING` with a type that has no such declaration is a compile error:

```iecst
TYPE Point : STRUCT x, y : DINT; END_STRUCT END_TYPE

FUNCTION main : DINT
VAR s : STRING; p : Point; END_VAR
s := TO_STRING(p); // error[E048]: Could not resolve reference to TO_STRING__Point
END_FUNCTION
```

## Calling C functions

`ST` code can call into foreign functions natively.
Expand Down
280 changes: 279 additions & 1 deletion libs/stdlib/iec61131-st/to_string.st
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,161 @@ FUNCTION TO_STRING__WSTRING : STRING[__STRING_LENGTH]
WSTRING_TO_STRING_EXT(in, TO_STRING__WSTRING);
END_FUNCTION

// Numeric, bit-string and date/time monomorphizations of the generic TO_STRING, each
// delegating to the corresponding typed <T>_TO_STRING conversion function.

FUNCTION TO_STRING__DINT : STRING[__STRING_LENGTH]
VAR_INPUT
in : DINT;
END_VAR

TO_STRING__DINT := DINT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LINT : STRING[__STRING_LENGTH]
VAR_INPUT
in : LINT;
END_VAR

TO_STRING__LINT := LINT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__USINT : STRING[__STRING_LENGTH]
VAR_INPUT
in : USINT;
END_VAR

TO_STRING__USINT := USINT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__UINT : STRING[__STRING_LENGTH]
VAR_INPUT
in : UINT;
END_VAR

TO_STRING__UINT := UINT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__UDINT : STRING[__STRING_LENGTH]
VAR_INPUT
in : UDINT;
END_VAR

TO_STRING__UDINT := UDINT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__ULINT : STRING[__STRING_LENGTH]
VAR_INPUT
in : ULINT;
END_VAR

TO_STRING__ULINT := ULINT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__BYTE : STRING[__STRING_LENGTH]
VAR_INPUT
in : BYTE;
END_VAR

TO_STRING__BYTE := BYTE_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__DWORD : STRING[__STRING_LENGTH]
VAR_INPUT
in : DWORD;
END_VAR

TO_STRING__DWORD := DWORD_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LWORD : STRING[__STRING_LENGTH]
VAR_INPUT
in : LWORD;
END_VAR

TO_STRING__LWORD := LWORD_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__REAL : STRING[__STRING_LENGTH]
VAR_INPUT
in : REAL;
END_VAR

TO_STRING__REAL := REAL_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LREAL : STRING[__STRING_LENGTH]
VAR_INPUT
in : LREAL;
END_VAR

TO_STRING__LREAL := LREAL_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__TIME : STRING[__STRING_LENGTH]
VAR_INPUT
in : TIME;
END_VAR

TO_STRING__TIME := TIME_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LTIME : STRING[__STRING_LENGTH]
VAR_INPUT
in : LTIME;
END_VAR

TO_STRING__LTIME := LTIME_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__DATE : STRING[__STRING_LENGTH]
VAR_INPUT
in : DATE;
END_VAR

TO_STRING__DATE := DATE_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LDATE : STRING[__STRING_LENGTH]
VAR_INPUT
in : LDATE;
END_VAR

TO_STRING__LDATE := LDATE_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__DT : STRING[__STRING_LENGTH]
VAR_INPUT
in : DT;
END_VAR

TO_STRING__DT := DT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LDT : STRING[__STRING_LENGTH]
VAR_INPUT
in : LDT;
END_VAR

TO_STRING__LDT := LDT_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__TOD : STRING[__STRING_LENGTH]
VAR_INPUT
in : TOD;
END_VAR

TO_STRING__TOD := TOD_TO_STRING(in);
END_FUNCTION

FUNCTION TO_STRING__LTOD : STRING[__STRING_LENGTH]
VAR_INPUT
in : LTOD;
END_VAR

TO_STRING__LTOD := LTOD_TO_STRING(in);
END_FUNCTION

// -----------------------------------------------------------------------------------------------------------
FUNCTION TO_WSTRING<T: ANY> : WSTRING[__STRING_LENGTH]
VAR_INPUT
Expand Down Expand Up @@ -122,4 +277,127 @@ FUNCTION TO_WSTRING__WCHAR : WSTRING[__STRING_LENGTH]
END_VAR

TO_WSTRING__WCHAR := WCHAR_TO_WSTRING(in);
END_FUNCTION
END_FUNCTION

// Numeric, bit-string and date/time monomorphizations of the generic TO_WSTRING, each
// delegating to the corresponding typed <T>_TO_WSTRING conversion function.

FUNCTION TO_WSTRING__DINT : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : DINT;
END_VAR

TO_WSTRING__DINT := DINT_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LINT : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LINT;
END_VAR

TO_WSTRING__LINT := LINT_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__BYTE : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : BYTE;
END_VAR

TO_WSTRING__BYTE := BYTE_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__DWORD : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : DWORD;
END_VAR

TO_WSTRING__DWORD := DWORD_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LWORD : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LWORD;
END_VAR

TO_WSTRING__LWORD := LWORD_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__REAL : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : REAL;
END_VAR

TO_WSTRING__REAL := REAL_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LREAL : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LREAL;
END_VAR

TO_WSTRING__LREAL := LREAL_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__TIME : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : TIME;
END_VAR

TO_WSTRING__TIME := TIME_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LTIME : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LTIME;
END_VAR

TO_WSTRING__LTIME := LTIME_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__DATE : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : DATE;
END_VAR

TO_WSTRING__DATE := DATE_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LDATE : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LDATE;
END_VAR

TO_WSTRING__LDATE := LDATE_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__DT : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : DT;
END_VAR

TO_WSTRING__DT := DT_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LDT : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LDT;
END_VAR

TO_WSTRING__LDT := LDT_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__TOD : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : TOD;
END_VAR

TO_WSTRING__TOD := TOD_TO_WSTRING(in);
END_FUNCTION

FUNCTION TO_WSTRING__LTOD : WSTRING[__STRING_LENGTH]
VAR_INPUT
in : LTOD;
END_VAR

TO_WSTRING__LTOD := LTOD_TO_WSTRING(in);
END_FUNCTION
Loading
Loading