4-ttcn3_language_extensions.adoc 371 KB
Newer Older
Elemer Lelik's avatar
Elemer Lelik committed
1
2
3
4
5
6
7
8
9
10
11
12
13
[[ttcn-3-language-extensions]]
= TTCN–3 Language Extensions
:toc:
:table-number: 3

The Test Executor supports the following non-standard additions to TTCN–3 Core Language in order to improve its usability or provide backward compatibility with older versions.

== Syntax Extensions

The compiler does not report an error or warning if the semi-colon is missing at the end of a TTCN–3 definition although the definition does not end with a closing bracket.

The statement block is optional after the guard operations of `altsteps`, `alt` and `interleave` constructs and in the response and exception handling part of `call` statements. A missing statement block has the same meaning as an empty statement block. If the statement block is omitted, a terminating semi-colon must be present after the guard statement.

14
The standard escape sequences of C/{cpp} programming languages are recognized and accepted in TTCN–3 character string values, that is, in literal values of `charstring` and `universal` `charstring` types, as well as in the arguments of built-in operations `log()` and `action()`.
Elemer Lelik's avatar
Elemer Lelik committed
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

NOTE: As a consequence of the extended escape sequences and in contrast with the TTCN–3 standard, the backslash character itself has to be always duplicated within character string values.

The following table summarizes all supported escape sequences of TTCN–3 character string values:

.Character string escape sequences
[cols=",,",options="header",]
|===
|*Escape sequence* |*Character code (decimal)* |*Meaning*
| |7 |bell
| |8 |backspace
| |12 |new page
| |10 |line feed
| |13 |carriage return
| |9 |horizontal tabulator
| 11 |vertical tabulator |
|\ |92 |backslash
|" |34 |quotation mark
33
|' |39 |apostrophe
Elemer Lelik's avatar
Elemer Lelik committed
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|? |63 |question mark
| <newline> |nothing |line continuation
| |NNN |octal notation (NNN is the character code in at most 3 octal digits)
| |NN |hexadecimal notation (NN is the character code in at most 2 hexadecimal digits)
|"" |34 |quotation mark (standard notation of TTCN–3 )
|===

NOTE: Only the standardized escape sequences are recognized in matching patterns of character string templates because they have special meaning there. For example, inside string patterns `\n` denotes a set of characters rather than a single character.

Although the standard requires that characters of TTCN–3 `charstring` values must be between 0 and 127, TITAN allows characters between 0 and 255. The printable representation of characters with code 128 to 255 is undefined.

The compiler implements an ASN.1-like scoping for TTCN–3 enumerated types, which means it allows the re-use of the enumerated values as identifiers of other definitions. The enumerated values are recognized only in contexts where enumerated values are expected; otherwise the identifiers are treated as simple references. However, using identifiers this way may cause misleading error messages and complicated debugging.

The compiler allows the local definitions (constants, variables, timers) to be placed in the middle of statement blocks, that is, after other behavior statements. The scope of such definitions extends from the statement following the definition to the end of the statement block. Forward-referencing of local definitions and jumping forward across them using `goto` statements are not allowed.

The compiler accepts in-line compound values in the operands of TTCN–3 expressions although the BNF of the standard allows only single values. The only meaningful use of the compound operands is with the comparison operators, that is, == and !=. Two in-line compound values cannot be compared with each other because their types are unknown; at least one operand of the comparison must be a referenced value. This feature has a limitation: In the places where in-line compound templates are otherwise accepted by the syntax (e.g. in the right-hand side of a variable assignment or in the actual parameter of a function call) the referenced value shall be used as the left operand of the comparison. Otherwise the parser gets confused when seeing the comparison operator after the compound value.

Examples:
[source]
----
// invalid since neither of the operands is of known type
if ({ 1, 2 } == { 2, 1 }) { }

// both are valid
while (v_myRecord == { 1, omit }) { }
if ({ f1 :=1, f2 := omit } != v_mySet) {}

// rejected because cannot be parsed
v_myBooleanFlag := { 1, 2, 3 } == v_myRecordOf;
f_myFunctionTakingBoolean({ 1, 2, 3 } != v_mySetOf);

// in reverse order these are allowed
v_myBooleanFlag := v_myRecordOf == { 1, 2, 3 };
f_myFunctionTakingBoolean(v_mySetOf != { 1, 2, 3 });
----

[[visibility-modifiers]]
== Visibility Modifiers

TITAN defines 3 visibility modifiers for module level definitions, and component member definitions: public, private, friend (8.2.5 in <<13-references.adoc#_1, [1]>>).

On module level definitions they mean the following:

* The public modifier means that the definition is visible in every module importing its module.
* The private modifier means that the definition is only visible within the same module.
* The friend modifier means that the definition is only visible within modules that the actual module declared as a friend module.

If no visibility modifier is provided, the default is the public modifier.

In component member definitions they mean the followings:

* The public modifier means that any function/testcase/altstep running on that component can access the member definition directly.
* The private modifier means that only those functions/testcases/altsteps can access the definition which runs on the component type directly. If they run on a component type extending the one containing the definition, it will not be directly visible.

The friend modifier is not available within component types.

Example:
[source]
----
module module1
{
import from module2 all;
import from module3 all;
import from module4 all;

const module2Type akarmi1 := 1; //OK, type is implicitly public
const module2TypePublic akarmi2 := 2; //OK, type is explicitly public
const module2TypeFriend akarmi3 := 3; //OK, module1 is friend of module2
const module2TypePrivate akarmi4 := 4; //NOK, module2TypePrivate is private to module2

const module3Type akarmi5 := 5; //OK, type is implicitly public
const module3TypePublic akarmi6 := 6; //OK, type is explicitly public
const module3TypeFriend akarmi7 := 7; //NOK, module1 is NOT a friend of module3
const module3TypePrivate akarmi8 := 8; //NOK, module2TypePrivate is private to module2

type component User_CT extends Lib4_CT {};
function f_set3_Lib4_1() runs on User_CT { v_Lib4_1 := 0 } //OK
function f_set3_Lib4_2() runs on User_CT { v_Lib4_2 := 0 } //OK
function f_set3_Lib4_3() runs on User_CT { v_Lib4_3 := 0 } //NOK, v_Lib4_3 is private
}

module module2
{

friend module module1;

type integer module2Type;
public type integer module2TypePublic;
friend type integer module2TypeFriend;
private type integer module2TypePrivate;
} // end of module

module module3
{
type integer module3Type;
public type integer module3TypePublic;
friend type integer module3TypeFriend;
private type integer module3TypePrivate;
} // end of module

module module4 {
type component Lib4_CT {
var integer v_Lib4_1;
public var integer v_Lib4_2;
private var integer v_Lib4_3;
}
----

== The `anytype`

The special TTCN-3 type `anytype` is defined as shorthand for the union of all known data types and the address type (if defined) in a TTCN-3 module. This would result in a large amount of code having to be generated for the `anytype`, even if it is not actually used. For performance reasons, Titan only generates this code if a variable of `anytype` is declared or used, and does not create fields in the `anytype` for all data types. Instead, the user has to specify which types are needed as `anytype` fields with an extension attribute at module scope.

Examples:

[source]
----
module elsewhere {
  type float money;
  type charstring greeting;
}
balaskoa's avatar
balaskoa committed
154
155
156
157
158
159
160
module local {
  import from elsewhere all;
  type integer money;
  type record MyRec {
    integer i,
    float f
  }
Elemer Lelik's avatar
Elemer Lelik committed
161
162
163
164
165
166

control {
  var anytype v_any;
  v_any.integer := 3;
  // ischosen(v_any.integer) == true

balaskoa's avatar
balaskoa committed
167
168
  v_any.charstring := "three";
  // ischosen(v_any.charstring) == true
Elemer Lelik's avatar
Elemer Lelik committed
169

balaskoa's avatar
balaskoa committed
170
171
172
  v_any.greeting := "hello";
  // ischosen(v_any.charstring) == false
  // ischosen(v_any.greeting) == true
Elemer Lelik's avatar
Elemer Lelik committed
173

balaskoa's avatar
balaskoa committed
174
175
  v_any.MyRec := { i := 42, f := 0.5 }
  // ischosen(v_any.MyRec) == true
Elemer Lelik's avatar
Elemer Lelik committed
176

balaskoa's avatar
balaskoa committed
177
178
179
180
181
182
  v_any.integer := v_any.MyRec.i – 2;
  // back to ischosen(v_any.integer) == true v_any.money := 0;
  // local money i.e. integer
  // not elsewhere.money (float)
  // ischosen(v_any.integer) == false
  // ischosen(v_any.money) == true
Elemer Lelik's avatar
Elemer Lelik committed
183

balaskoa's avatar
balaskoa committed
184
185
  // error: no such field (not added explicitly)
  // v_any.float := 3.1;
Elemer Lelik's avatar
Elemer Lelik committed
186

balaskoa's avatar
balaskoa committed
187
  // error: v_any.elsewhere.money
Elemer Lelik's avatar
Elemer Lelik committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
 }
}

with {

extension "anytype integer, charstring" // adds two fields
extension "anytype MyRec" // adds a third field
extension "anytype money" // adds the local money type
//not allowed: extension "anytype elsewhere.money"
extension "anytype greeting" // adds the imported type}
----

In the above example, the `anytype` behaves as a union with five fields named "integer", "charstring", "MyRec", "money" and "greeting". The anytype extension attributes are cumulative; the effect is the same as if a single extension attribute contained all five types.

NOTE: Field "greeting" of type charstring is distinct from the field "charstring" even though they have the same type (same for "integer" and "money").

Types imported from another module (elsewhere) can be added to the anytype of the importing module (local) if the type can be accessed with its unqualified name, which requires that it does not clash with any local type. In the example, the imported type "greeting" can be added to the anytype of module local, but "money" (a float) clashes with the local type "money" (an integer). To use the imported "money", it has to be qualified with its module name, for example a variable of type elsewhere.money can be declared, but elsewhere.money can not be used as an anytype field.

== Ports and Test Configurations

208
If all instances of a TTCN–3 port type are intended to be used for internal communication only (i.e. between two TTCN–3 test components) the generation and linking of an empty Test Port skeleton can be avoided. If the attribute `with { extension "internal" }` is appended to the port type definition, all {cpp} code that is needed for this port will be included in the output modules.<<13-references.adoc#_9, [9]>>
Elemer Lelik's avatar
Elemer Lelik committed
209

210
If the user wants to use `address` values in `to` and `from` clause and sender redirect of TTCN–3 port operations the `with { extension "address" }` attribute shall be used in the corresponding port type definition(s) to generate proper {cpp} code.
Elemer Lelik's avatar
Elemer Lelik committed
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

NOTE: When address is used in port operations the corresponding port must have an active mapping to a port of the test system interface, otherwise the operation will fail at runtime. Using of address values in to and from clauses implicitly means system as component reference. (See section "Support of address type" in <<13-references.adoc#_16, [16]>> for more details).<<13-references.adoc#_10, [10]>>

Unlike the latest TTCN–3 standard, our run time environment allows to connect a TTCN–3 port to more than one ports of the same remote test component. When these connections persist (usually in transient states), only receiving is allowed from that remote test component, because the destination cannot be specified unambiguously in the `to` clause of the `send` operation. Similarly, it is allowed to map a TTCN–3 port to more than one ports of the system, although it is not possible to send messages to the SUT.

[[parameters-of-create-operation]]
== Parameters of create Operation

The built-in TTCN–3 `create` operation can take a second, optional argument in the parentheses. The first argument, which is the part of the standard, can assign a name to the newly created test component. The optional, non-standard second argument specifies the location of the component. Also the second argument is a value or expression of type `charstring`.

According to the standard the component name is a user-defined attribute for a test component, which can be an arbitrary string value containing any kind of characters including whitespace. It is not necessary to assign a unique name for each test component; several active test components can have the same name at the same time. The component name is not an identifier; it cannot be used to address test components in configuration operations as component references can. The name can be assigned only at component creation and it cannot be changed later.

Component name is useful for the following purposes:

* it appears in the printout when logging the corresponding component reference;
* it can be incorporated in the name of the log file (see the metacharacter `%n`);
* it can be used to identify the test component in the configuration file (when specifying test port parameters (see section <<7-the_run-time_configuration_file.adoc#logging, `[LOGGING]`>>), component location constraints (see section <<7-the_run-time_configuration_file.adoc#components-parallel-mode, [COMPONENTS] (Parallel mode)>>) and logging options (see sections <<7-the_run-time_configuration_file.adoc#filemask, `FileMask`>> and <<7-the_run-time_configuration_file.adoc#consolemask, `ConsoleMask`>>).

Specifying the component location is useful when performing distributed test execution. The value used as location must be a host name, a fully qualified domain name, an IP address or the name of a host group defined in the configuration file (see section <<7-the_run-time_configuration_file.adoc#groups-parallel-mode, [GROUPS] (Parallel mode)>>). The explicit specification of the location overrides the location constraints given in the configuration file (see section <<7-the_run-time_configuration_file.adoc#components-parallel-mode, [COMPONENTS] (Parallel mode)>> for detailed description). If no suitable and available host is found the `create` operation fails with a dynamic test case error.

If only the component name is to be specified, the second argument may be omitted. If only the component location is specified a `NotUsedSymbol` shall be given in the place of the component name.

Examples:

[source]
----
//create operation without arguments
var MyCompType v_myCompRef := MyCompType.create;

// component name is assigned
v_myCompRef := MyCompType.create("myCompName");

// component name is calculated dynamically
v_myCompArray[i] := MyCompType.create("myName" & int2str(i));

// both name and location are specified (non-standard notation)
v_myCompRef := MyCompType.create("myName", "heintel");

// only the location is specified (non-standard notation)
v_myCompRef := MyCompType.create(-, "159.107.198.97") alive;
----

== Altsteps and Defaults

According to the TTCN–3 standard an `altstep` can be activated as `default` only if all of its value parameters are `in` parameters. However, our compiler and run-time environment allows the activation of altsteps with `out` or `inout` value or template parameters as well. In this case the actual parameters of the activated `default` shall be the references of variables or template variables that are defined in the respective component type. This restriction is in accordance with the rules of the standard about timer parameters of activated defaults.

NOTE: Passing local variables or timers to defaults is forbidden because the lifespan of local definitions might be shorter than the `default` itself, which might lead to unpredictable behavior if the `default` is called after leaving the statement block that the local variable is defined in. Since ports can be defined only in component types, there is no restriction about the `port` parameters of `altsteps`. These restrictions are not applicable to direct invocations of `altsteps` (e.g. in `alt` constructs).

The compiler allows using a statement block after `altstep` instances within `alt` statements. The statement block is executed if the corresponding `altstep` instance was chosen during the evaluation of the alt statement and the `altstep` has finished without reaching a `repeat` or `stop` statement. This language feature makes the conversion of TTCN–2 test suites easier.

NOTE: This construct is valid according to the TTCN–3 BNF syntax, but its semantics are not mentioned anywhere in the standard text.

The compiler accepts `altsteps` containing only an `[else]` branch. This is not allowed by the BNF as every `altstep` must have at least one regular branch (which can be either a guard statement or an `altstep` instance). This construct is practically useful if the corresponding `altstep` is instantiated as the last branch of the alternative.

== Interleave Statements

The compiler realizes TTCN–3 `interleave` statements using a different approach than it is described in section 7.5 of <<13-references.adoc#_1, [1]>>. The externally visible behavior of the generated code is equivalent to that of the canonical mapping, but our algorithm has the following advantages:

Kristof Szabados's avatar
Kristof Szabados committed
269
* Loop constructs `for`, `while` and `do-while` loops are accepted and supported without any restriction in `interleave` statements. The transformation of statements is done in a lower level than the TTCN–3 language, which does not restrict the embedded loops.
Elemer Lelik's avatar
Elemer Lelik committed
270
* Statements `activate`, `deactivate` and `stop` can also be used within `interleave`. The execution of these statements is atomic so we did not see the reason why the standard forbids them.
271
* The size of our generated code is linear in contrast to the exponential code growth of the canonical algorithm. In other words, the {cpp} equivalent of every embedded statement appears exactly once in the output.
Elemer Lelik's avatar
Elemer Lelik committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
* The run-time realization does not require any extra operating system resources, such as multi-threading.

== Logging Disambiguation

The TTCN–3 log statement provides the means to write logging information to a file or display on console (standard error). Options <<7-the_run-time_configuration_file.adoc#filemask, `FileMask`>> and <<7-the_run-time_configuration_file.adoc#consolemask, `ConsoleMask`>> determine which events will appear in the file and on the console, respectively. The generated logging messages are of type `USER_UNQUALIFIED`.

The `log` statement accepts among others fixed character strings TTCN–3 constants, variables, timers, functions, templates and expressions; for a complete list please refer to the table 18 in <<13-references.adoc#_1, [1]>>. It is allowed to pass multiple arguments to a single `log` statement, separated by commas.

The TTCN-3 standard does not specify how logging information should be presented. The following sections describe how TITAN implemented logging.

The arguments of the TTCN-3 statement `action` are handled according to the same rules as `log`.

=== Literal Free Text String

Strings entered between quotation marks (") <<13-references.adoc#_11, [11]>> and the results of special macros given in section <<ttcn3-macros, TTCN-3 Macros>> in the argument of the `log` statement are verbatim copied to the log. The escape sequences given in Table 4 are interpreted and the resulting non-printable characters (such as newlines, tabulators, etc.) will influence the printout.

Example:

[source]
----
log("foo");//The log printout will look like this:
 12:34:56.123456 foo
 bar
----

=== TTCN-3 Values and Templates

Literal values, referenced values or templates, wildcards, compound values, in-line (modified) templates, etc. (as long as the type of the expression is unambiguous) are discussed in this section.

These values are printed into the log using TTCN-3 Core Language syntax so that the printout can be simply copied into a TTCN-3 module to initialize an appropriate constant/variable/template, etc.

In case of (`universal`) `charstring` values the delimiter quotation marks ("") are printed and the embedded non-printable characters are substituted with the escape sequences in the first 9 rows of Table 4. All other non-printable characters are displayed in the TTCN-3 quadruple notation.

If the argument refers to a constant of type `charstring`, the actual value is not substituted to yield a literal string.

Example:

[source]
----
const charstring c_string := "foo\000";
log(c_string);
//The log printout will look like this:
12:34:56.123456 "foo" & char(0, 0, 0, 0)
----

=== Built-in Function match()

For the built-in `match()` function the printout will contain the detailed matching process field-by-field (similarly to the failed `receive` statements) instead of the Boolean result.

This rule is applied only if the` match()` operation is the top-level expression to be logged, see the example below:

[source]
----
 // this will print the detailed matching process
log(match(v_myvalue, t_template));
 // this will print only a Boolean value (true or false)
log(not not match(v_myvalue, t_template));
----
All the other predefined and user-defined functions with actual arguments will print the return value of the function into the log according to the TTCN-3 standard.

=== Special TTCN-3 Objects

If the argument refers to a TTCN-3 `port`, `timer` or array (slice) of the above, then the actual properties of the TTCN-3 object is printed into the log.

For ports the name and the state of the port is printed.

In case of timers the name of the timer, the default duration, the current state (`inactive`, `started` or `expired`), the actual duration and the elapsed time (if applicable) is printed in a structured form.

== Value Returning done

The compiler allows starting TTCN–3 functions having return type on PTCs. Those functions must have the appropriate `runs on` clause. If such a function terminates normally on the PTC, the returned value can be matched and retrieved in a `done` operation.

344
According to the TTCN-3 standard, the value redirect in a `done` operation can only be used to store the local verdict on the PTC that executed the behavior function. In TITAN the value redirect can also be used to store the behavior function's return value with the help of an optional template argument.
Elemer Lelik's avatar
Elemer Lelik committed
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378

If this template argument is present, then the compiler treats it as a value returning done operation, otherwise it is treated as a verdict returning `done`.

The following rules apply to the optional template argument and the value redirect:

* The syntax of the template and value redirect is identical with that of the `receive` operation.
* If the template is present, then the type of the template and the variable used in the value redirect shall be identical. If the template is not present, then the type of the value redirect must be `verdicttype`.
* In case of a value returning done the return type shall be a TTCN–3 type marked with the following attribute: `with { extension "done" }`. It is allowed to mark and use several types in done statements within one test suite. If the type to be used is defined in ASN.1 then a type alias shall be added to one of the TTCN–3 modules with the above attribute.
* In case of a value returning done the type of the template or variable must be visible from the module where the `done` statement is used.
* Only those done statements can have a template or a value redirect that refer to a specific PTC component reference. That is, it is not allowed to use this construct with `any component.done` or `all component.done`.

A value returning `done` statement is successful if all the conditions below are fulfilled:

* The corresponding PTC has terminated.
* The function that was started on the PTC has terminated normally. That is, the PTC was stopped neither by itself nor by other component and no dynamic test case error occurred.
* The return type of the function that was started on the PTC is identical to the type of the template used in the `done` statement.
* The value returned by the function on the PTC matches the given template.

If the `done` operation was successful and the value redirect is present the value returned by the PTC (if there was a matching template), or the local verdict on the PTC (if there was no matching template) is stored in the given variable or variable field.

The returned value can be retrieved from `alive` PTCs, too. In this case the `done` operation always refers to the return value of the lastly started behavior function of the PTC. Starting a new function on the PTC discards the return value of the previous function automatically (i.e. it cannot be retrieved or matched after the start component operation anymore).

Example:

[source]
----
type integer MyReturnType with { extension "done" };

function ptcBehavior() runs on MyCompType return MyReturnType
{
  setverdict(inconc);
  return 123;
}

379
// value returning 'done'
Elemer Lelik's avatar
Elemer Lelik committed
380
381
382
383
384
385
386
387
388
testcase myTestCase() runs on AnotherCompType
{
  var MyReturnType myVar;
  var MyCompType ptc := MyCompType.create;
  ptc.start(ptcBehavior());
  ptc.done(MyReturnType : ?) -> value myVar;
  // myVar will contain 123
}

389
// verdict returning 'done'
Elemer Lelik's avatar
Elemer Lelik committed
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
testcase myTestCase2() runs on AnotherCompType
{
  var verdicttype myVar;
  var MyCompType ptc := MyCompType.create;
  ptc.start(ptcBehavior());
  ptc.done -> value myVar;
  // myVar will contain inconc
}
----

== Dynamic Templates

Dynamic templates (template variables, functions returning templates and passing template variables by reference) are now parts of the TTCN–3 Core Language standard (<<13-references.adoc#_1, [1]>>). These constructs have been added to the standard with the same syntax and semantics as they were supported in this Test Executor. Thus dynamic templates are not considered language extensions anymore.

However, there is one extension compared to the supported version of Core Language. Unlike the standard, the compiler and the run-time environment allow the external functions to return templates.

Example:

[source]
----
// this is not valid according to the standard
external function MyExtFunction() return template octetstring;
----

== Template Module Parameters

The compiler accepts template module parameters by inserting an optional "template" keyword into the standard modulepar syntax construct between the modulepar keyword and the type reference. The extended BNF rule:

[source,subs="+quotes"]
419
ModuleParDef ::= "modulepar" (ModulePar | ("{"MultiTypedModuleParList "}"))ModulePar ::= *["template"]* Type ModuleParList
Elemer Lelik's avatar
Elemer Lelik committed
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449

Example:

[source]
----
modulepar template charstring mp_tstr1 := ( "a" .. "f") ifpresent
modulepar template integer mp_tint := complement (1,2,3)
----

== Predefined Functions

The built-in predefined functions `ispresent`, `ischosen`, `lengthof` and `sizeof` are applicable not only to value-like language elements (constants, variables, etc.), but template-like entities (templates, template variables, template parameters) as well. If the function is allowed to be called on a value of a given type it is also allowed to be called on a template of that type with the meaning described in the following subchapters.

NOTE: "dynamic test case error" does not necessarily denote here an error situation: it may well be a regular outcome of the function.

=== `sizeof`

The function `sizeof` is applicable to templates of `record`, `set`, `record` of, `set` `of` and `objid` types. The function is applicable only if the `sizeof` function gives the same result on all values that match the template.<<13-references.adoc#_12, [12]>> In case of `record of` and `set of` types the length restrictions are also considered. Dynamic test case error occurs if the template can match values with different sizes or the length restriction contradicts the number of elements in the template body.

Examples:

[source]
----
type record of integer R;
type set S { integer f1, bitstring f2 optional, charstring f3 optional }
template R tr_1 := { 1, permutation(2, 3), ? }
template R tr_2 := {1, *, (2, 3) }
template R tr_3 := { 1, *, 10 } length(5)
template R tr_4 := { 1, 2, 3, * } length(1..2)
template S tr_5 := { f1 := (0..99), f2 := omit, f3 := ? }
450
template S tr_6 := { f3 := *, f1 := 1, f2 := '00'B ifpresent }
Elemer Lelik's avatar
Elemer Lelik committed
451
template S tr_7 := ({ f1 := 1, f2 := omit, f3 := "ABC" },
452
                  { f1 := 2, f3 := omit, f2 := '1'B })
Elemer Lelik's avatar
Elemer Lelik committed
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
template S tr_8 := ?

//sizeof(tr_1) → 4
//sizeof(tr_2) → error
//sizeof(tr_3) → 5
//sizeof(tr_4) → error
//sizeof(tr_5) → 2
//sizeof(tr_6) → error
//sizeof(tr_7) → 2
//sizeof(tr_8) → error
----

=== `ispresent`

The predefined function `ispresent` has been extended; its parameter can now be any valid TemplateInstance. It is working according to the following ETSI CRs: http://forge.etsi.org/mantis/view.php?id=5934 and http://forge.etsi.org/mantis/view.php?id=5936.

=== `oct2unichar`

The function `oct2unichar` (`in octetstring invalue`, `in charstring string_encoding := "UTF-8"`) `return universal charstring` converts an octetstring `invalue` to a universal charstring by use of the given `string_encoding`. The octets are interpreted as mandated by the standardized mapping associated with the given `string_encoding` and the resulting characters are appended to the returned value. If the optional `string_encoding` parameter is omitted, the default value "UTF-8".

The following values are allowed as `string_encoding` actual parameters: `UTF8`, `UTF-16`, `UTF-16BE`, `UTF-16LE`, `UTF-32`, `UTF-32BE`, `UTF-32LE`.

DTE occurs if the `invalue` does not conform to UTF standards. The `oct2unichar` checks if the Byte Order Mark (BOM) is present. If not a warning will be appended to the log file. `oct2unichar` will `decode` the invalue even in absence of the BOM.

Any code unit greater than 0x10FFFF is ill-formed.

UTF-32 code units in the range of 0x0000D800 – 0x0000DFFF are ill-formed.

UTF-16 code units in the range of 0xD800 – 0xDFFF are ill-formed.

UTF-8 code units in the range of 0xD800 – 0xDFFF are ill-formed.

Example:
----
oct2unichar('C384C396C39CC3A4C3B6C3BC'O)="ÄÖÜäöü";oct2unichar('00C400D600DC00E400F600FC'O,"UTF-16LE") = "ÄÖÜäöü";
----

=== `unichar2oct`

The function `unichar2oct` (`in universal charstring invalue, in charstring string_encoding := "UTF-8"`) `return octetstring` converts a universal charstring `invalue` to an octetstring. Each octet of the octetstring will contain the octets mandated by mapping the characters of `invalue` using the standardized mapping associated with the given `string_encoding` in the same order as the characters appear in inpar. If the optional `string_encoding` parameter is omitted, the default encoding is "UTF-8".

The following values are allowed as `string_encoding` actual parameters: UTF-8, UTF-8 BOM, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, UTF-32LE.

The function `unichar2oct` adds the Byte Order Mark (BOM) to the beginning of the `octetstring` in case of `UTF-16` and `UTF-32` encodings. The `remove_bom` function helps to remove it, if it is not needed. The presence of the BOM is expected at the inverse function `oct2unichar` because the coding type (without the BOM) can be detected only in case of `UTF-8` encoded `octetstring`. By default UTF-8 encoding does not add the BOM to the `octetstring`, however `UTF-8` `BOM` encoding can be used to add it.

DTE occurs if the `invalue` does not conform to UTF standards.

Any code unit greater than 0x10FFFF is ill-formed.

Example:

[source]
----
unichar2oct("ÄÖÜäöü") = 'EFBBBFC384C396C39CC3A4C3B6C3BC'O;
unichar2oct("ÄÖÜäöü","UTF-16LE") = 'FFFE00C400D600DC00E400F600FC'O;
----

[[get-stringencoding]]
=== `get_stringencoding`

The function `get_stringencoding (in octetstring encoded_value) return charstring` identifies the encoding of the `encoded_value`. The following return values are allowed as charstring: ASCII, UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE.

If the type of encoding could not been identified, it returns the value: <unknown>

Example:

[source]
----
var octetstring invalue := 'EFBBBFC384C396C39CC3A4C3B6C3BC'O;
var charstring codingtype := get_stringencoding(invalue);
the resulting codingtype is "UTF-8"
----

[[remove-bom]]
=== `remove_bom`

The function `remove_bom (in octetstring encoded_value) return octetstring` strips the BOM if it is present and returns the original octetstring otherwise.

Example:

[source]
----
var octetstring invalue := 'EFBBBFC384C396C39CC3A4C3B6C3BC'O;
var octetstring nobom := remove_bom(invalue);
the resulting nobom contains: 'C384C396C39CC3A4C3B6C3BC'O;
----

== Additional Predefined Functions

In addition to standardized TTCN–3 predefined functions given in Annex C of <<13-references.adoc#_1, [1]>> and Annex B of <<13-references.adoc#_3, [3]>> the following built-in conversion functions are supported by our compiler and run-time environment:

=== `str2bit`

The function `str2bit (charstring value) return bitstring` converts a `charstring` value to a `bitstring`, where each character represents the value of one bit in the resulting bitstring. Its argument may contain the characters "0" or "1" only, otherwise the result is a dynamic test case error.

NOTE: This function is the reverse of the standardized `bit2str`.

Example:

[source]
553
str2bit ("1011011100") = '1011011100'B
Elemer Lelik's avatar
Elemer Lelik committed
554
555
556
557
558
559
560
561
562
563
564

=== `str2hex`

The function `str2hex (charstring value)` `return hexstring` converts a `charstring` value to a `hexstring`, where each character in the character string represents the value of one hexadecimal digit in the resulting `hexstring`. The incoming character string may contain any number of characters. A dynamic test case error occurs if one or more characters of the charstring are outside the ranges "0" .. "9", "A" .. "F" and "a" .. "f".

NOTE: This function is the reverse of the standardized `hex2str`.

Example:

[source]
----
565
str2hex ("1D7") = '1D7'H
Elemer Lelik's avatar
Elemer Lelik committed
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
----

=== float2str

The function `float2str (float value) return charstring` converts a `float` value to a `charstring`. If the input is zero or its absolute value is between 10^-4^ and 10^10^, the decimal dot notation is used in the output with 6 digits in the fraction part. Otherwise the exponential notation is used with automatic (at most 6) digits precision in the mantissa.

Example:

[source]
----
float2str (3.14) = "3.140000"
----

=== unichar2char

The function `unichar2char (universal charstring value) return charstring` converts a` universal charstring` value to a `charstring`. The elements of the input string are converted one by one. The function only converts universal characters when the conversion result lies between 0 end 127 (that is, the result is an ISO 646 character).

NOTE: The inverse conversion is implicit, that is, the `charstring` values are converted to `universal charstring` values automatically, without the need for a conversion function.

Example:

[source]
----
unichar2char(char(0,0,0,64)) = "@"
----

=== `log2str`

The function `log2str` can be used to log into `charstring` instead of the log file.

Syntax:

[source]
log2str (…) return charstring

601
This function can be parameterized in the same way as the `log` function, it returns a charstring value which contains the log string for all the provided parameters, but it does not contain the timestamp, severity and call stack information, thus the output does not depend on the runtime configuration file. The parameters are interpreted the same way as they are in the log function: their string values are identical to what the log statement writes to the log file. The extra information (timestamp, severity, call stack) not included in the output can be obtained by writing external functions which use the runtime's Logger class to obtain the required data.
Elemer Lelik's avatar
Elemer Lelik committed
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651

=== `testcasename`

The function `testcasename` returns the unqualified name of the actually executing test case. When it is called from the control part and no test case is being executed, it returns the empty string.

Syntax:

[source]
testcasename () return charstring

=== `isbound`

The function `isbound` behaves identically to the `isvalue` function with the following exception: it returns true for a record-of value which contains both initialized and uninitialized elements.

[source]
----
type record of integer rint;
var rint r_u; // uninitialized
isvalue(r_u); // returns false
isbound(r_u); // returns false also
//lengthof(r_u) would cause a dynamic testcase error

var rint r_0 := {} // zero length
isvalue(r_3); // returns true
isbound(r_3); // returns true
lengthof(r_3); // returns 0

var rint r_3 := { 0, -, 2 } // has a "hole"
isvalue(r_3); // returns false
isbound(r_3); // returns true
lengthof(r_3); // returns 3

var rint r_3full := { 0, 1, 2 }
isvalue(r_3full); // returns true
isbound(r_3full); // returns true
lengthof(r_3full); // returns 3
----

The introduction of `isbound` permits TTCN-3 code to distinguish between r_u and r_3; `isvalue` alone cannot do this (it returns false for both).

Syntax:
[source]
isbound (in template any_type i) return boolean;

=== `ttcn2string`

Syntax:
[source]
ttcn2string(in <TemplateInstance> ti) return charstring

652
This predefined function returns its parameter's value in a string which is in TTCN-3 syntax. The returned string has legal ttcn-3 with a few exceptions such as unbound values. Unbound values are returned as "-", which can be used only as fields of assignment or value list notations, but not as top level assignments (e.g. `x:=- is illegal`). Differences between the output format of `ttcn2string()` and `log2str()`:
Elemer Lelik's avatar
Elemer Lelik committed
653
654
655
656

[cols=",,",options="header",]
|===
|Value/template |`log2str()` |`ttcn2string()`
657
658
|Unbound value |`"<unbound>"` |"-"
|Uninitialized template |`"<uninitialized template>"` |"-"
Elemer Lelik's avatar
Elemer Lelik committed
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
|Enumerated value |`name (number)` |name
|===

=== `string2ttcn`

Syntax:

[source]
string2ttcn(in charstring ttcn_str, inout <reference> ref)

This predefined function does not have a return value, thus it is a statement. Any error in the input string will cause an exception that can be caught using @try - @catch blocks. The message string of the exception contains the exact cause of the error. There might be syntax and semantic errors. This function uses the module parameter parser of the TITAN runtime, it accepts the same syntax as the module parameters of the configuration file. Check the documentation chapters for the module parameters section. There are differences between the ttcn-3 syntax and the configuration file module parameters syntax, these are described in the documentation chapter of the module parameters. The second parameter must be a reference to a value or template variable.

Example code:

[source]
----
type record MyRecord { integer a, boolean b }

var template MyRecord my_rec
@try {
  string2ttcn("complement ({1,?},{(1,2,3),false}) ifpresent", my_rec)
  log(my_rec)
  }
  @catch (err_str) {
683
    log("string2ttcn() failed: ", err_str)
Elemer Lelik's avatar
Elemer Lelik committed
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
  }

The log output will look like this:
complement ({ a := 1, b := ? }, { a := (1, 2, 3), b := false }) ifpresent
----

[[encode-base64]]
=== `encode_base64`

Syntax:

[source]
----
encode_base64(in octetstring ostr, in boolean
  use_linebreaks := false) return charstring
----

The function `encode_base64 (in octetstring ostr, in boolean use_linebreaks := false) return charstring `converts an octetstring `ostr` to a charstring. The charstring will contain the Base64 representation of `ostr`. The `use_linebreaks` parameter adds newlines after every 76 output characters, according to the MIME specs, if it is omitted, the default value is false.

Example:

[source]
----
encode_base64('42617365363420656E636F64696E6720736368656D65'O) ==
"QmFzZTY0IGVuY29kaW5nIHNjaGVtZQ=="
----

[[decode-base64]]
=== `decode_base64`

Syntax:

[source]
----
decode_base64(in charstring str) return octetstring
----

Kristof Szabados's avatar
Kristof Szabados committed
721
The function `decode_base64 (in charstring str) return octetstring` converts a charstring `str` encoded in Base64 to an octetstring. The octetstring will contain the decoded Base64 string of `str`.
Elemer Lelik's avatar
Elemer Lelik committed
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745

Example:

[source]
----
decode_base64("QmFzZTY0IGVuY29kaW5nIHNjaGVtZQ==") ==
'42617365363420656E636F64696E6720736368656D65'O
----

=== `json2cbor`

Syntax:

[source]
----
json2cbor(in universal charstring us) return octetstring
----

The function `json2cbor(in universal charstring us) return octetstring` converts a TITAN encoded json document into the binary representation of that json document using a binary coding called CBOR. The encoding follows the recommendations written in the CBOR standard <<13-references.adoc#_22, [22]>> section 4.2.

Example:

[source]
----
746
json2cbor("{"a":1,"b":2}") == 'A2616101616202'O
Elemer Lelik's avatar
Elemer Lelik committed
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
----

=== `cbor2json`

Syntax:
[source]
----
cbor2json(in octetstring os) return universal charstring
----

The function `cbor2json(in octetstring os) return universal charstring` converts a CBOR encoded bytestream into a json document which can be decoded using the built in JSON decoder. The decoding follows the recommendations written in the CBOR standard <<13-references.adoc#_22, [22]>> section 4.1 except that the indefinite-length items are not made definite before conversion and the decoding of indefinite-length items is not supported.

Example:
[source]
----
762
cbor2json('A2616101616202'O) == "{"a":1,"b":2}"
Elemer Lelik's avatar
Elemer Lelik committed
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
----

=== `json2bson`

Syntax:
[source]
----
json2bson(in universal charstring us) return octetstring
----

The function `json2bson(in universal charstring us) return octetstring` converts a TITAN encoded json document into the binary representation of that json document using a binary coding called BSON. Only top level json objects and arrays can be encoded. (Note that an encoded top level json array will be decoded as a json object) The encoding follows the rules written in the BSON standard <<13-references.adoc#_23, [23]>>. The encoding handles the extension rules written in the MongoDB Extended JSON document <<13-references.adoc#_24, [24]>>. The encoding of 128-bit float values is not supported.

Example:
[source]
----
778
json2bson("{"a":1,"b":2}") == '13000000106100010000001062000200000000'O
Elemer Lelik's avatar
Elemer Lelik committed
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
----

=== `bson2json`

Syntax:
[source]
----
bson2json(in octetstring os) return universal charstring
----

The function `bson2json(in octetstring os) return universal charstring` converts a BSON encoded bytestream into a json document which can be decoded using the built in JSON decoder. The decoding follows the extension rules written in the BSON standard <<13-references.adoc#_23, [23]>>. The decoding handles the rules written in the MongoDB Extended JSON document <<13-references.adoc#_24, [24]>>. The decoding of 128-bit float values is not supported.

Example:
[source]
----
794
bson2json('13000000106100010000001062000200000000'O) == "{"a":1,"b":2}"
Elemer Lelik's avatar
Elemer Lelik committed
795
796
797
798
799
800
801
802
803
----

== Exclusive Boundaries in Range Subtypes

The boundary values used to specify range subtypes can be preceded by an exclamation mark. By using the exclamation mark the boundary value itself can be excluded from the specified range. For example integer range (!0..!10) is equivalent to range (1..9). In case of float type open intervals can be specified by using excluded boundaries, for example (0.0..!1.0) is an interval which contains 0.0 but does not contain 1.0.

[[special-float-values-infinity-and-not-a-number]]
== Special Float Values Infinity and not_a_number

804
The keyword infinity (which is also used to specify value range and size limits) can be used to specify the special float values –infinity and +infinity, these are equivalent to MINUS-INFINITY and PLUS-INFINITY used in ASN.1. A new keyword not_a_number has been introduced which is equivalent to NOT-A-NUMBER used in ASN.1. The -infinity and +infinity and not_a_number special values can be used in arithmetic operations. If an arithmetic operation's operand is not_a_number then the result of the operation will also be not_a_number. The special value not_a_number cannot be used in a float range subtype because it's an unordered value, but can be added as a single value, for example subtype (0.0 .. infinity, not_a_number) contains all positive float values and the not_a_number value.
Elemer Lelik's avatar
Elemer Lelik committed
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882

[[ttcn-3-preprocessing]]
== TTCN–3 Preprocessing

Preprocessing of the TTCN-3 files with a C preprocessor is supported by the compiler. External preprocessing is used: the Makefile Generator generates a `Makefile` which will invoke the C preprocessor to preprocess the TTCN-3 files with the suffix `."ttcnpp`. The output of the C preprocessor will be generated to an intermediate file with the suffix `."ttcn`. The intermediate files contain the TTCN-3 source code and line markers. The compiler can process these line markers along with TTCN-3. If the preprocessing is done with the `-P` option <<13-references.adoc#_13, [13]>>, the resulting code will not contain line markers; it will be compatible with any standard TTCN-3 compiler. The compiler will use the line markers to give almost <<13-references.adoc#_14, [14]>> correct error or warning messages, which will point to the original locations in the `.ttcnpp` file. The C preprocessor directive `#"include` can be used in .ttcnpp files; the Makefile Generator will treat all files with suffix `."ttcnin` as TTCN-3 include files. The `."ttcnin` files will be added to the Makefile as special TTCN-3 include files which will not be translated by the compiler, but will be checked for modification when building the test suite.

Extract from the file:
[source]
----
Example.ttcnpp:
module Example {
function func()
{
#ifdef DEBUG
log("Example: DEBUG");
#else
log("Example: RELEASE");
#endif

}


----

The output is a preprocessed intermediate file `Example.ttcn`. The resulting output from the above code:
[source]
----

# 1 "Example.ttcnpp"
module Example {
function func()
{
log("Example: RELEASE");
}
----

The line marker (`# 1 "Example.ttcnpp"`) tells the compiler what the origin of the succeeding code is.

== Parameter List Extensions

In addition to standardized TTCN-3 parameter handling described in 5.4.2 of <<13-references.adoc#_1, [1]>> TITAN also supports the mixing of list notation and assignment notation in an actual parameter list.

=== Missing Named and Unnamed Actual Parameters

To facilitate handling of long actual parameter lists in the TITAN implementation, the actual parameter list consists of two optional parts: an unnamed part followed by a named part, in this order. In the actual parameter list a value must be assigned to every mandatory formal parameter either in the named part or in the unnamed part. (Mandatory parameter is one without default value assigned in the formal parameter list.) Consequently, the unnamed part, the named part or both may be omitted from the actual parameter list. Omitting the named part from the actual parameter lists provides backward compatibility with the standard notation.

The named and unnamed parts are separated by a comma as are the elements within both lists. It is not allowed to assign value to a given formal parameter in both the named and the unnamed part of the actual parameter list.

There can be at most one unnamed part, followed by at most one named part. Consequently, an unnamed actual parameter may not follow a named parameter.

Named actual parameters must follow the same relative order as the formal parameters. It is not allowed to specify named actual parameters in an arbitrary order.

Examples

The resulting parameter values are indicated in brackets in the comments:

[source]
----
function myFunction(integer p_par1, boolean p_par2 := true) { … }
control {
*// the actual parameter list is syntactically correct below:*
myFunction(1, p_par2 := false); // (1, false)
myFunction(2); // (2, true)
myFunction(p_par1 := 3, p_par2 := false); // (3, false)
*// the actual parameter list is syntactically erroneous below:*
myFunction(0, true, -); // too many parameters
myFunction(1, p_par1 := 1); // p_par1 is given twice
myFunction(); // no value is assigned to mandatory p_par1
myFunction(p_par2 := false, p_par1 := 3); // out of order
myFunction(p_par2 := false, 1); // unnamed part cannot follow
// named part
}
----

== `function`, `altstep` and `testcase` References

Although TITAN supports the behaviour type package (<<13-references.adoc#_5, [5]>>) of the TTCN-3 standard, but this feature was included in the standard with a different syntax.

Kristof Szabados's avatar
Kristof Szabados committed
883
It is allowed to create TTCN–3 types of `functions`, `altsteps` and `testcases`. Values, for example variables, of such types can carry references to the respective TTCN–3 definitions. To facilitate reference using, three new operations (`refers`, `derefers` and `apply`) were introduced. This new language feature allows to create generic algorithms in TTCN–3 with late binding, (i.e. code in which the function to be executed is specified only at runtime).
Elemer Lelik's avatar
Elemer Lelik committed
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000

[[function-types-with-a-runson-self-clause]]
== Function Types with a RunsOn_self Clause

A function type or an altstep type, defined with a standard `runs on` clause, can use all constants, variables, timers and ports given in the component type definition referenced by the `runs on` clause (see chapter 16 of <<13-references.adoc#_1, [1]>>).

A function type or an altstep type, defined with the TITAN-introduced `runs on self` clause, similarly, makes use of the resources of a component type; however, the component type in question is not given in advance. When an altstep or a function is called via a function variable, that is, a reference, using the `apply` operation, it can use the resources defined by the component type indicated in the `runs on` clause of the actually referenced function or altstep.

The "runs on self" construct is permitted only for `function` and `altstep` types. Any actual function or altstep must refer to a given component type name in their `runs on` clause.

A variable with type of function type is called a *function variable*. Such variables can contain references to functions or altsteps. At function variable assignment, component type compatibility checking is performed with respect to the component context of the assignment statement and the "runs on" clause of the assigned function or altstep. When the `apply()` operator is applied to a function variable, no compatibility checking is performed.

The rationale for this distinction is the following: due to type compatibility checking at the time of value assignment to the function variable, the TTCN-3 environment can be sure that any non-`null` value of the variable is a function reference that is component-type-compatible with that component that is actually executing the code using the `apply()` operator.

As a consequence of this, it is forbidden to use values of function variables as arguments to the TTCN-3 operators `start()` or `send()`.

Example of using the clause `runs on self` in a library

A component type may be defined as an extension of another component type (using the standard `extends` keyword mentioned in chapter 6.2.10.2 of <<13-references.adoc#_1, [1]>>). The effect of this definition is that the extended component type will implicitly contain all constant, variable, port and timer definitions from the parent type as well. In the example below, the component type `User_CT` aggregates its own constant, variable, port and timer definitions (resources) with those defined in the component type `Library_CT` (see line a).

The library developer writes a set of library functions that have a `runs on Library_CT` clause (see line h). Such library functions may offer optional references to other functions that are supposed to be specified by the user of the library (see line e). We say in this case that the library function may call user-provided *callback functions* via function variables. These function variables must have a type specified; optionally with a runs on clause. If this `runs on` clause refers to an actual component type name, then this actual type name must be known at the time of writing the library.

Library functions that runs on `Library_CT` can run on other component types as well, provided that the actual component type is compatible with `Library_CT` (see chapter 6.3.3 of <<13-references.adoc#_1, [1]>>). An obvious design goal for the library writer is to permit references to any callback function that has a component-type-compatible `runs on` clause. However, the cardinality of compatible component types is infinitely large; therefore, they *cannot* be explicitly referenced by the function type definitions of the library.

The "runs on self" concept provides a remedy for this contradiction and allows conceiving library components prepared to take up user-written "plug-ins".

In the code excerpt below, function `f_LibraryFunction` (which has the clause `runs on Library_CT`) uses the function reference variable `v_callBackRef_self` (defined in `Library_CT`).The function `f_MyCallbackFunction` (see line b) has a `runs on User_CT` clause. `User_CT` (see line a) extends `Library_CT`, therefore it is suitable for running library function with runs on `Library_CT` clause, for example.

When the assignment to the function variable `v_CallbackRef_self` is performed (see line c) inside `f_MyUserFunction` (that is, inside the context `User_CT`), then compatibility checking is performed. Since `User_CT` is compatible with `Library_CT`, the assignment is allowed.

Direct call to `f_MyCallbackFunction()` with `runs on User_CT` from a `runs on Library_CT` context (see line g) would cause semantic error according to the TTCN3 language. However, calling the function via `v_CallBackRef_self` is allowed (see line d).

[source]
----
module RunsOn_Self
{
//=========================================================================
// Function Types
//=========================================================================

//---- line f)
type function CallbackFunctionRefRunsonSelf_FT () runs on self;

//=========================================================================
//Component Types
//=========================================================================
type component Library_CT
{
//---- line e)
  var CallbackFunctionRefRunsonSelf_FT v_CallbackRef_self := null;
  var integer v_Lib;
}
//---- line a)
type component User_CT extends Library_CT
{
  var integer v_User;
}

//---- line h)
function f_LibraryFunction () runs on Library_CT
{
//---- line g)
  // Direct call of the callback function would cause semantic ERROR
//f_MyCallbackFunction();

  if (v_CallbackRef_self != null)
  {
    // Calling a function via reference that has a "runs on self" in its header
    // is always allowed with the exception of functions/altsteps without runs
    // on clause
//---- line d)
    v_CallbackRef_self.apply();
  }
}// end f_LibraryFunction

function f_MyUserFunction () runs on User_CT
{
  // This is allowed as f_MyCallbackFunction has runs on clause compatible
  // with the runs on clause of this function (f_MyUserFunction)
  // The use of function/altstep references with "runs on self" in their
  // headers is limited to call them on the given component instance; i.e.
  // allowed: assignments, parameterization and activate (the actual function's
  //          runs on is compared to the runs on of the function in which
  //          the operation is executed)
  // not allowed: start, sending and receiving
  // no check is needed for apply!
//---- line c)
  v_CallbackRef_self := refers (f_MyCallbackFunction);

  // This is allowed as Library_CT is a parent of User_CT
  // Pls. note, as the function is executing on a User_CT
  // instance, it shall never cause a problem of calling
  // a callback function with "runs on User_CT" from it.
  f_LibraryFunction();

}//end f_MyUserFunction

//---- line b)
function f_MyCallbackFunction () runs on User_CT
{/*application/dependent behaviour*/}

} // end of module RunsOn_Self
----

[[ttcn3-macros]]
== TTCN–3 Macros

The compiler and the run-time environment support the following non-standard macro notation in TTCN–3 modules. All TTCN–3 macros consist of a percent (%) character followed by the macro identifier. Macro identifiers are case sensitive. The table below summarizes the available macros and their meaning. Macro identifiers not listed here are reserved for future extension.

.TTCN-3 macros
[cols=",",options="header",]
|===
|Macro |Meaning
|`%moduleId` |name of the TTCN–3 module
|`%definitionId` |name of the top-level TTCN–3 definition
|`%testcaseId` |name of the test case that is currently being executed
|`%fileName` |name of the TTCN–3 source file
For faster browsing, not all history is shown. View entire blame