Abstract State Machines

Abstract state machines (ASMs) provide a high-level means for assembling complex transformation programs.

ASM functions

ASM functions provide a non-persistent map to store values. Each ASM function needs to be declared prior to its first use. Initial values can also be set when defining an ASM function. The values stored at a certain location of an ASM function can be updated using the update ASM construct (see later).

machine asmFuns {
 asmfunction team / 2 {
     // Initialization
 	(1, "real") = "Casillas";
 	(7, "real") = "Raul";
 	// Any values are allowed to be used in the untyped version
 	(7.1, 6) = 2;
 }
 asmfunction anotherFun / 1; // An ASM function without initialization
}

In the new (upcoming) VIATRA2 version, types can also be defined for ASM functions as follows.

 // Import is needed if types are intended to be used by local names
 import datatypes;
 machine asmFuns {
  asmfunction team(Integer, datatypes.String) : String  { // FQNs can always be used for defining types
 	(1, "real") = "Casillas";
 	(7, "real") = "Raul";
 	// The following initialization would be a type error
       // (7.1, 6) = 2;
  }
  rule main() = seq 
  {
 	update team(1, "mu") = "van der sar";
  }
 }

User defined ASM rules

Users can define ASM rules as means for encapsulating certain functionality as a reusable operation. A user-defined ASM rule has an arbitrary number of parameters with the following directions:

An optional type can be associated to each parameter of a user-defined ASM rule, which refers to an existing model element within the model space (i.e. existing at compile time).

 import datatypes;
 machine callrules_01{
  rule test(in X:String , out Y, inout Z) = seq { 
 	update Y = X+Z;
 	print(X + Y + Z); // prints "aacc"
  } 
  rule main() = seq{
 	call test("a", "b", "c"); 
  }
 }

The further use of user-defined ASM rules are illustrated in the following example:

 machine symParams
 {
  rule main() = seq
  {
	let A=1, B=2, C=undef in seq {
 		call myRule(A,B,C);
 		println(A + "," + B + "," +C); // 1,1,2
 		call myRule(3,B,C);
 		println(3 + "," + B + "," +C); // 3,3,6
 		call myRule(A,B,A); 
 		println(A + "," + B + "," +A); // 2,1,2
 	}
  }
  rule myRule(in A, inout B, out C) = seq
  {
 	update B = A;
 	update C = A + B;
  }
}

Simple rules

Simple rules include the following elementary ASM control structures:

 machine simple_rules {
  rule main(in X) = seq {
	skip; 
 	print("abc"); 
 	log(error, "Error");
 	update X = "sec";
  }
 }

Composite rules

Composite rules allow to assemble more complex transformation algorithms. Composite control structures in VTCL are as follows:

Example for using if rule

 machine ifrules_01{
  rule main (in X)= seq {
  	print(X);
 	if (X == 10) print("OK:if"); 
 	else print("ERR:else");
 	if (X != 10) print("ERR:if"); 
 	else print("OK:else");
  }
 }

Example for using try rule

 machine tryrules_01{
  rule testing(in X)= seq {
 	if (X == 4) fail;
 	print(X);
  }
  rule main ()= seq {
	try call testing(2); 
 	else print("ERR");

try call testing(4); else print("OK");

  }
 }

Example for choose rule with ASM functions as conditions (more examples will be given for GT patterns)

 import datatypes;
 machine chooserules_01{
 // Untyped version	
  asmfunction testFunc/1 {("a") = 1; ("b") = 2; ("c") = 3;}
  rule main() = seq{
 	choose Y with (testFunc(Y) > 1) do seq{
 		if (Y == "b" || Y == "c") print("OK");
 		else print("ERR");
 	}

call myRule1();

  }
 // Typed version
  asmfunction testFunc2(String): Integer {("a") = 1; ("b") = 2; ("c") = 3;}
  rule myRule1() = seq{
 	choose Y: String with (testFunc(Y) > 1) do seq{
 		if (Y == "b" || Y == "c") print("OK");
 		else print("ERR");
 	}	
  }
 }

Example for forall rule with ASM functions as conditions (more examples will be given for GT patterns)

 machine forallrules_01{
  asmfunction testFunc/1 {("a") = 1; ("b") = 2; ("c") = 3;}
  rule main() = let C1 = false, C2 = false in seq{
 	forall Y with (testFunc(Y) > 1) do seq{
 		if (Y == "b") update C1 = true;			
 		if (Y == "c") update C2 = true;
 	}		
 	if (C1 == true && C2 == true) print("OK");
 	else print("ERR");
 	call forallRule1();	
  }
  asmfunction testFunc2 (datatypes.String) : datatypes.Integer {("a") = 1; ("b") = 2; ("c") = 3;}
  rule forallRule1 () = let C1 = false, C2 = false in seq{
 	forall Y with (testFunc2(Y) > 1) do seq{
 		if (Y == "b") update C1 = true;			
 		if (Y == "c") update C2 = true;
 	}		
 	if (C1 == true && C2 == true) print("OK");
 	else print("ERR");	
  }
 }