Documentation of TTCN-3 templates for TRex implementers and TRex JUnit test authors

The TTCN-3 template constructs supports a lot of different types of templates. In particular for the different refactorings related to templates, all the possible cases and pitfalls need to be considered. To make sure that both TRex implementers and TRex JUnit test authors do not miss a case, this page describes several possible cases of templates.

Note that a lot of concepts are orthogonally to each other, hence only a few representative cases are considered here. Feel free to add further cases.

On the left hand side of the assignment char, any combination of the following variants may occur:

  1. Message based vs. Procedure based:
    1. Template for a type
      1. Predefined type
      2. Referenced type
    2. Template for a signature
  2. Parametrisation:
    1. Unparametrised Template
    2. Parametrised Template (only in parameter allowed)
      1. Types as formal parameter
      2. Templates as formal parameter
  3. Derived/Modified Template
    1. modifies (Parametrisation of derived and modified template is a bit tricky, see example section below)
    2. no modifies

On the right hand side of the assignment char, the template body may consist of:

(SimpleSpec | FieldSpecList | ArrayValueOrAttrib) [ExtraMatchingAttributes] (The standard says
(SimpleSpec | FieldSpecList | ArrayValueOrAttrib) | [ExtraMatchingAttributes] which must be an error since this would allow an empty template body.) The ExtraMatchingAttributes are only applicable in templates used for receiving.

An overwhelming number of different template bodies may occur. Consider this, when writing refactorings involving templates. Do not try to manually re-construct a template. You will certainly fail and not cover all cases. Either perform transformations only on the AST subtree of that template and use the pretty printer to obtain textual representation of this AST subtree or copy completely the textual representation of a template body and replace selected locations by textual representations of smaller AST subtrees (e.g. the subtree of a parameter) using the pretty printer'''

Please refer to the BNF for further details. (You are invited to add extend this description, in particular mentioning pitfalls.)

Examples (JUnit test shall cover as much as possible of them):

// Templates for some Predefined types
template bitstring bitstringTemplate := {'1100'B};

template boolean booleanTemplate := {true};

template charstring charstringTemplate := {"bar"};

template integer integerTemplate := {42};

template universal charstring universalCharstringTemplate := { "" };

template integer integerWildcardTemplate := ?; 

template integer integerEnumeratedTemplate := (1, 2, 3);

template integer integerRangeTemplate := (1..10);


// Template for signature
signature RemoteProc(in integer Par1, out integer Par2, inout integer Par3) return integer;

template RemoteProc Template1:= 
{
	Par1 := 1, 
	Par2 := 2, 
	Par3 := 3 
}


// A template for an empty record
type record MyMessageType {}

template MyMessageType MyMessage := {}


// Some template for a record
type record myTypeA {
	charstring elementA,
	integer elementB
}
	
template myTypeA templateA := {
	elementA := "test",
	elementB := 2
}


// Derived template using modifies
template myTypeA templateB modifies templateA := {
	elementB := 4
}


// Inline template using modifies
type record myRecordTypeA4 {
	integer field1,
	charstring field2,
	boolean field3
}

template myRecordTypeA4 Setup := 
{ 
	field1 := 75,
	field2 := "abc", 
	field3 := true 
}

//function Function1462() runs on xyz
//{
//	pco1.send (modifies Setup := {field1 := 76});
//}


// Parametrised template
type record myTypeA2 {
	charstring elementA,
	integer elementB,
	charstring elementC
}
	
template myTypeA2 templateA2(charstring p1, integer p2) := {
	elementA := "test",
	elementB := p2,
	elementC := p1
}


// Parametrisation of modified templates
type record myRecordTypeA3 {
	integer field1,
	charstring field2,
	boolean field3
}

template MyRecordType3 MyParametrisedTemplate1(integer Mypar):= 
{
	field1 := MyPar, 
	field2 := "A string", 
	field3 := true 
}

template MyRecordTyp3e MyParametrisedTemplate1(integer MyPar) modifies MyParametrisedTemplate1 := //Error: Do not use "()"!
{ // field1 is parameterised in Template1
	field2 := "A modified string", 
	field3 := false
}


// Templates as parameters
type record MyMessageType3 
{
	integer field1 optional, 
	charstring field2, 
	boolean field3 
}

template MyMessageType3 MyTemplate3 (template integer MyFormalParam):= 
{ 
	field1 := MyFormalParam,
	field2 := pattern "abc*xyz", 
	field3 := true 
}

// might be referenced using: 
//function Function1462() runs on xyz
//{
// pco1.receive(MyTemplate3(?)); 
//}

// Nested templates
type record myTypeA3 {
	charstring elementA,
	integer elementB,
	charstring elementC
}

type record myTypeB3 {
	myTypeA3 A
}
	
template myTypeA3 templateA3(charstring p1, integer p2) := {
	A := {
		elementA := "test",
		elementB := p2,
		elementC := p1
	}
}

template myTypeB3 templateB3 := {
    	A := templateA3("TEST", 10)
}

// More nested templates
type record mySecondType {
	charstring secondTypeElementOne,
	integer secondTypeElementTwo
}
	
type record myType {
	charstring firstTypeElementOne,
	mySecondType firstTypeElementTwo
}

template myType myTemplate := {
	firstTypeElementOne := "test",
	firstTypeElementTwo := {
		secondTypeElementOne := "test2",
		secondTypeElementTwo := 4
	}
}


// Templates referencing other template
template address_t address_merged := {
    address := "192.168.0.1"
};

template address_t address0 := address_merged;

template address_t address1 := address_merged; 



// Template involving set of and nesting
type record GenericParam {
    charstring id,
    charstring paramValue
}

type set of GenericParam parlist;

type record From {
    charstring foo,
    parlist bar
}

template From test := {
    foo := "bla",
    bar := {{
        id := "test",
        paramValue := "test1"
    }}
}; 

// More templates involving set of and furhter nesting
type record blala {
    charstring fooo,
    integer baaar
}

type record GenericParam {
    charstring id,
    charstring paramValue,
    blala third
}

type set of GenericParam parlist;

type record From {
    charstring foo,
    parlist bar
}

template From test := {
    foo := "bla",
    bar := {{
        id := "test",
        paramValue := "test1",
        third := {
            fooo := "test",
            baaar := 2
        }
    }}
}


// A template using pattern
type record MyMessageType2 
{
	integer field1, 
	charstring field2, 
	boolean field3 
}

template MyMessageType2 MyTemplate2(integer MyValue) :=
{
	field1 := MyValue, 
	field2 := pattern "abc*xyz",
	field3 := true 
}

TBD: Add examples based on the following type and template definitions (refer to the standard Section 6.3 and Annex B where these examples are taken from):

// record of / set of
type record length(10) of integer MyRecordOfType; // is a record of exactly 10 integers

type record length(0..10) of integer MyRecordOfType; // is a record of a maximum of 10 integers

type record length(10..infinity) of integer MyRecordOfType; // record of at least 10 integers

type set of boolean MySetOfType; // is an unlimited set of boolean values

type record length(0..10) of charstring StringArray length(12); 
// is a record of a maximum of 10 strings each with exactly 12 characters


type record of enumerated { red, green, blue } ColorList;

type record length (10) of record length (10) of integer Matrix;

type set of record { charstring id, charstring val } GenericParameters;


// Given
type record of integer MyRecordOf;
var integer MyVar;
var MyRecordOf MyRecordVar := { 0, 1, 2, 3, 4 };
MyVar := MyRecordVar[0]; // the first element of the "record of" value (integer 0)
// is assigned to MyVar

// Indexed values are permitted on the left-hand side of assignments as well:
MyRecordVar[1] := MyVar; // MyVar is assigned to the second element
// value of MyRecordVar is { 0, 0, 2, 3, 4 }

// The assignment
MyRecordVar := { 0, 1, -, 2, omit };
// will change the value of MyRecordVar to{ 0, 1, 2 <unchanged>, 2};
// Note, that the 3rd element would be undefined if had had no previous assigned value.


// set is same as record just without any order of the fields, 
// hence assignments can be done using a different order and value list notation is forbidden
type set MySetType
{
	integer field1,
	charstring field2
}

// record type with nested structured type definitions
type record MyNestedRecordType
{
	record
	{
		integer nestedField1,
		float nestedField2
	} outerField1,
	enumerated {
		nestedEnum1,
		nestedEnum2
	} outerField2,
	record of boolean outerField3
}


// Union
type union MyUnionType
{
	integer number,
	charstring string
};

// ExtraMatching Attributes

TBD: add an example using the ExtraMatchingAttributes ::= LengthMatch | IfPresentMatch | LengthMatch IfPresentMatch


// Matching attributes for values inside templates
type set of integer MySetOfType;

template MySetOfType MyTemplate1 := superset ( 1, 2, 3 );
// any sequence of integers matches which contains at least one occurrences of the numbers
// 1, 2 and 3 in any order and positions


type record of integer MySequenceOfType;

template MySequenceOfType MyTemplate1 := { permutation ( 1, 2, 3 ), 5 };
// matches any of the following sequences of 4 integers: 1,2,3,5; 1,3,2,5; 2,1,3,5;
// 2,3,1,5; 3,1,2,5; or 3,2,1,5
template MySequenceOfType MyTemplate9 := { permutation ( 1, 2, *) length (3..5), 5 };
// matches any sequence of four to six integers that ends with 5 and contains 1 and 2 at least
// once in other position


template Mymessage MyTemplate:=
{
	field1 := complement ({4,5},{1,4,8,9}) length (1 .. 6), // any value containing 1, 2, 3, 4,
	// 5 or 6 elements is accepted provided it is not {4,5} or {1,4,8,9}
	field2 := "ab*ab" length(13) // max length of the AnyElementsOrNone string is 9 characters
	:
}

template Mymessage MyTemplate:=
{
	:
	field2 := "abcd" ifpresent, // matches "abcd" if not omitted
	:
	:
}

Note that parameters of templates may be not only references and constants, but expressions in general. Be prepared to cope with the following (in the examples below, this are not parameters to templates, but for predefined types. But in general this is also applicable to template parameters):

MyPCO.send(MyVariable + YourVariable - 2) to MyPartner; 
// Sends the result of the arithmetic expression to MyPartner.


MyPort.receive(A<B); 
// Specifies the reception of a Boolean value true or false depending on the outcome of A<B

MyPort.receive(integer:MyVar); 
// Specifiess the reception of an integer value which has the same value as the variable MyVar 
// at MyPort. The (optional) type identifier integer is not strictly necessary because the 
// type is already given by the definition of MyVar. However, in complex and long test cases 
// such a type identifier may be used to improve readability.
	
MyPort.receive(MyVar); 
// Is an alternative to the previous example.