# P Expressions

A Function in P can be arbitrary piece of imperative code which enables programmers to capture complex protocol logic in their state machines. P supports the common imperative programming language expressions (just like in Java).

## P Expressions Grammar

```
expr :
| (expr) # ParenExpr
| primitiveExpr # PrimitiveExpr
| formatedString # FormatStringExpr
| (tupleBody) # TupleExpr
| (namedTupleBody) # NamedTupleExpr
| expr.int # TupleAccessExpr
| expr.iden # NamedTupleAccessExpr
| expr[expr] # AccessExpr
| keys(expr) # KeysExpr
| values(expr) # ValuesExpr
| sizeof(expr) # SizeofExpr
| expr in expr # ContainsExpr
| default(type) # DefaultExpr
| new iden ( rvalueList? ) # NewExpr
| iden ( rvalueList? ) # FunCallExpr
| (- | !) expr # UnaryExpr
| expr (* | / | + | -) expr # ArithBinExpr
| expr (== | !=) expr # EqualityBinExpr
| expr (&& | ||) expr # LogicalBinExpr
| expr (< | > | >= | <= ) expr # CompBinExpr
| expr as type # CastExpr
| expr to type # CoerceExpr
| choose ( expr? ) # ChooseExpr
;
# Formated strings for creating strings
formatedString
| format ( StringLiteral (, rvalueList)? )
;
primitiveExpr
: iden # Identifier
| FloatLiteral # FloatConstant
| BoolLiteral # BooleanConstant
| IntLiteral # IntConstant
| NullLiteral # Null
| StringLiteral # StringConstant
| $ # BooleanNonDeterministicChoice
| halt # HaltEvent
| this # SelfMachineReference
;
# Body of a tuple
tupleBody :
| rvalue ,
| rvalue (, rvalue)+
;
# Body of a named tuple
namedTupleBody:
| iden = rvalue ,
| iden = rvalue (, iden = rvalue)+
;
# r-value is an expression that canâ€™t have a value assigned to it which
# means r-value can appear on right but not on left hand side of an assignment operator(=)
rvalue : expr ;
# rvalueList is a comma separated list of rvalue.
```

### Primitives

P allows the common primitive expressions like literal-constants for integers, floats, strings, booleans, and the null value. There are three unique primitive expressions in P:

#### $

`$`

represents a nondeterministic boolean choice. It is a short hand for `choose()`

which randomly returns a boolean value and the P Checker explores the behavior of the system for both the possibilities i.e., both when `$`

evaluates to `true`

or `false`

.

#### Halt

`halt`

is a special event in P used for destroying an instance of a P machine. The semantics of an `halt`

event is that whenever a P machine throws an `unhandled event`

exception because of a `halt`

event then the machine is automatically destroyed or halted and all events sent to that machine instance there after are equivalent to being dropped to ether. There are two ways of using the `halt`

event: (1) **self-halt** by doing `raise halt;`

raising a `halt`

event which is not handled in the state machine will lead to that machine being halted or (2) by sending the `halt`

event to a machine, and that machine on dequeueing `halt`

, would halt itself. Please checkout the FailureDetector example in tutorials to know more about halt event

#### This

`this`

represents the `self`

machine reference of the current machine. It can be used to send self reference to other machines in the program so that they can send messages to this machine.

### Formatted String

P allows creating formatted strings.

**Syntax:**: `format ( formatString (, rvalueList)? )`

`formatString`

is the format string and `rvalueList`

is a comma separated list of arguments for the formatted string.

```
var hw, h, w: string;
var tup: (string, int);
h = "Hello"; w = "World";
tup = ("tup value", 100);
hw = format("{0} {1}, and {2} is {3}!",
h, w, tup.0, tup.1);
// hw value is "Hello World, and tup value is 100!"
```

Formatted strings are most useful for printing logs. Checkout `print`

statement.

```
var hw, h, w: string;
var tup: (string, int);
h = "Hello"; w = "World";
tup = ("tup value", 100);
print format("{0} {1}, and {2} is {3}!",
h, w, tup.0, tup.1);
// prints "Hello World, and tup value is 100!"
```

### Tuple and Named Tuple Values

A tuple or named tuple value can be created using the following expressions:

**Syntax (tuple value):**: `(rvalue ,)`

for a single field tuple value or `(rvalue (, rvalue)+)`

for tuple with multiple fields.

```
// tuple value of type (int,)
(10,)
// tuple value of type (string, (string, string))
("Hello", ("World", "!"))
// assume x: int and y: string
// tuple value of type (int, string)
(x, y)
```

**Syntax (named tuple value):**: `(iden = rvalue ,)`

for a single field named tuple value or `(iden = rvalue (, iden = rvalue)+)`

for named tuple with multiple fields.

```
// named tuple value of type (reqId: int,)
(reqId = 10,)
// named tuple value of type (h: string, (w: string, a: string))
(h = "Hello", (w = "World", a = "!"))
// assume x: int and y: string
// named tuple value of type (a:int, b:string)
(a = x, b = y)
```

### Access Field of Tuple and Named Tuple

The fields of a tuple can be
accessed by using the `.`

operation followed by the field index.

**Syntax (tuple value):** `expr.int`

where `expr`

is the tuple value and `int`

is the field index.

```
// tuple with three fields
var tupleEx: (int, bool, int);
tupleEx = (20, false, 21);
// accessing the first and third element of the tupleEx
tupleEx.0 = tupleEx.0 + tupleEx.2;
```

Named tuples are similar to tuples with each field having an associated name. The fields
of a named tuple can be accessed by using the `.`

operation followed by the field name.

**Syntax (named tuple value)**: `expr.iden`

where `expr`

is the named tuple value and `iden`

is the field name.

```
// named tuple with three fields
var namedTupleEx: (x1: int, x2: bool, x3: int);
namedTupleEx = (x1 = 20, x2 = false, x3 = 21);
// accessing the first and third element of the namedTupleEx
namedTupleEx.x1 = namedTupleEx.x1 + namedTupleEx.x3;
```

### Indexing into a Collection

P supports three collection types: `map`

, `seq`

, and `set`

. We can index into these collection types to access its elements.

**Syntax:** `expr_c[expr_i]`

If `expr_c`

is a value of sequence type then `expr_i`

must be an integer expression and `expr_c[expr_i]`

represents the element at index `expr_i`

. Similarly, If `expr_c`

is a value of set type then `expr_i`

must be an integer expression and `expr_c[expr_i]`

represents the element at index `expr_i`

but note that for a set there is no guarantee for the order in which elements are stored in the set.
Finally, if `expr_c`

is a value of map type then `expr_i`

represents the key to look up and `expr_c[expr_i]`

represents the value for the key `expr_i`

.

### Operations on Collections

P supports four other operations on collection types:

#### sizeof

**Syntax:**: `sizeof(expr)`

, where `expr`

is a value of type `set`

, `seq`

or `map`

, returns an integer value representing the size or length of the collection.

```
var sq: seq[int];
while (i < sizeof(sq)>) {
...
i = i + 1;
}
```

#### keys and values

Programmers can use `keys`

and `values`

functions to get access to a sequence of all the keys or values in map respectively.

**Syntax:**: `keys(expr)`

or `values(expr)`

`expr`

must be a map value, if `expr : map[K, V]`

then `keys(expr)`

returns a sequence of all keys in the map (of type `seq[K]`

) and similarly, `values(expr)`

returns a sequence of all values in the map (of type `seq[V]`

).

Primarily, `keys`

and `values`

are used to get contents of the map and then operate over it.

#### contains (or `in`

)

To check if an element (or key in the case of a map) belongs to a collection, P provides the `in`

operation.

**Syntax:** `expr_e in expr_c`

`expr_e`

is the element (or key in the case of map) and `expr_c`

is the collection value. The `in`

expression evaluates to `true`

if the element belongs to the collection and `false`

otherwise.

```
var sq: seq[tRequest];
var mp: map[int, tRequest];
var rr: tRequest; var i: int;
...
if(rr in sq && rr in values(mp) && i in mp) { ... }
```

### Default value for a type

The `default`

primitive in P can be used to obtain the default value for any type.

**Syntax:** `default(type)`

`type`

is any P type and `default(type)`

represents the default value for the `type`

. The default values for all P types is provided here.

### New

New expression is used to create an instance of a machine, `new`

returns a machine reference to the newly created instance of the machine.

**Syntax**: `new iden (rvalue?) ;`

`iden`

is the name of the machine to be created and `rvalue`

is the optional constructor parameter that becomes the input parameter of the entry function of the start state of the machine.

```
new Client((id = 1, server = this));
```

`(id = 1, server = this)`

which is delivered as a payload to the entry function of the start state of the created Client machine.
### Function Call

Function calls in P are similar to any other imperative programming languages.

Note that the parameters passed to the functions and the return values are pass-by-value!

**Syntax**: `iden ( rvalueList? ) ;`

`iden`

is the name of the function and `rvalueList`

is the comma separated list of function arguments.

```
x = Foo();
y = Bar(10, "haha");
```

### Negation and Not

P supports two unary operations: `-`

on integers and floats values (i.e., negation) and `!`

on boolean values (i.e., logical not).

### Arithmetic

P supports the following arithmetic binary operations on integers or floats: `+`

(i.e., addition), `-`

(i.e., subtraction), `*`

(i.e., multiplication), `%`

(i.e., modulo), and `/`

(i.e., division).

### Comparison

P supports the following comparison binary operations on integers or floats: `<`

(i.e., less-than), `<=`

(i.e., less-than-equal), `>`

(i.e., greater-than), and `>=`

(i.e., greater-than-equal).

### Cast

P supports two super types `any`

and `data`

(more details). To cast values from these supertypes to the actual types, P supports the `as`

cast expression.

**Syntax:** `expr as T`

`expr`

expression is cast to type `T`

and if the cast is not valid then it leads to dynamic type-cast error.

```
type tRecord = (key: int, val: any);
...
var st: set[tRecord];
var x: any;
var x_i: string;
var st_i: set[(key: int, val: string)];
x_i = x as string;
st += ((key = 1, val = "hello"));
st_i = st as set[(key: int, val: string)];
...
```

### Coerce

P supports coercing of any value of type `float`

to `int`

and also any `enum`

element to `int`

.

**Syntax:** `expr to T`

`expr`

expression is coerced to type `T`

. We currently support only coercing of type `float`

to `int`

and also any `enum`

element to `int`

.

```
enum Status {
ERROR = 101,
SUCCESS = 102
}
...
var x_f : float;
var x_i: int;
x_f = 101.0;
x_i = x_f to int;
assert x_i == ERROR to int;
```

### Choose

P provides the `choose`

primitive to model data nondeterminism in P programs. The P checker then explores the behavior of the program for all possible values that can be returned by the `choose`

operation.

**Syntax:** `choose()`

or `choose(expr)`

`expr`

can either be a `int`

value or a collection. For `choose(x)`

, when `x`

is an integer, `choose(x)`

returns a random value between `0 to x`

(excluding x), when `x`

is a collection then `choose(x)`

returns a random element from the collection.

```
choose() // returns true or false, is equivalent to $
choose(10) // returns an integer x, 0 <= x < 10
choose(x) // if x is set or seq then returns a value from that collection
```

The choose operation can be used to model nondeterministic environment machines that generate random inputs for the system. Another use case could be to model nondeterministic behavior within the system itself where the system can randomly choose to `timeout`

or `fail`

or `drop messages`

.

Performing a `choose`

over an empty collection leads to an error. Also, `choose`

from a `map`

value returns a random key from the map.