Fork me on GitHub

PGo logo PGo

Outline

This page describes the current state of our Modular PlusCal specification.

Abstract

This page describes the current state of our Modular PlusCal specification. Modular PlusCal allows the specification writer to more clearly separate abstract and implementation-dependent details, allowing the PGo compiler to generate source code that is easy to change and enables the evolution of specification and implementation to happen at the same time.

This was originally discussed in Github issue #75.

This document describes language syntax and limitations associated with each feature.

Syntax

Modular PlusCal (MPCal) is comprised of three features: archetypes, mapping macros, and references. MPCal algorithms are declared in .tla files as comments as below:

---- MODULE DistributedProtocol ----
EXTENDS Integers, Sequeneces, TLC

CONSTANTS A, B, C

(************************
--mpcal DistributedProtocol {
\* Modular PlusCal specification
}
************************)
====================================

MPCal is compiled by PGo to vanilla PlusCal, which is turn translated to TLA+ by the TLA+ toolbox. Temporal properties and invariants can then be written as usual.

Archetypes

Archetypes describe the behavior of the processes being specified. They are declared as such:

archetype Coordinator(connection)
variables local = 10, success = FALSE;
{
    l1: statement1;
    l2: statement2;
}

Archetypes look a lot like PlusCal processes (syntactically speaking). However, they differ in key aspects:

On the other hand, archetypes share some similarities with PlusCal processes:

Archetypes are used when processes are defined based on them: this is called instantiation:

CONSTANTS COORDINATORS, BACKUPS

variables connection = <<>>,
          backupConnection = <<>>;

process (MainCoordinator \in COORDINATORS) == instance Coordinator(connection);
process (BackupCoordinator \in BACKUPS) == instance Coordinator(backupConnection);

In the definition above, the connection variable is global in PlusCal. However, when PGo compiles an specification like the one above, only source code for archetypes is generated. Archetype parameters represent implementation-specific details that need to be filled in by the developer (oftentimes, the PGo runtime will provide most of the logic required in these implementation-specific components).

Mapping Macros

Mapping macros allow developers to isolate model-checking behavior from archetypes. They are simple wrappers for non-determinism and abstractions.

Suppose we want to model a network that is both lossy and reordering (emulating UDP semantics in concrete environments). MPCal enables the specification developer to write this behavior as a mapping macro:

mapping macro LossyReorderingNetwork {
    read {
        with (msg \in $variable) {
            $variable := $variable \ msg;
            yield msg;
        }
    }

    write {
        either { yield $variable } or { yield Append($variable, $value) };
    }
}

The mapping macro above introduces a number of related concepts:

Mapping macros are supposed to be thin wrappers and, as such, operate under several restrictions:

Once defined, mapping macros can be used during instantiation, mapping variables passed to archetypes:

process MainCoordinator == instance Coordinator(connection)
    mapping connection via LossyReorderingNetwork;

References

References is an extension to parameter passing in PlusCal that makes mutation intent explicit. In particular, they are used when an archetype modifies one of its arguments and also allowing procedures to modify its parameters (not possible in PlusCal).

Assignments to non-local variables in archetypes and procedures can only happen if the argument is passed as a reference:

procedure inc(ref counter) {
    i: counter := counter + 1;
       return;
}

archetype Counter(ref counter) {
    call inc(ref counter);
}

variable n = 0;
process CounterProcess == instance Counter(ref n);

In the example above, the keyword ref is used to indicate that n is passed as a reference to the archetype definition, which is then able to pass it as a reference to the inc procedure, which modifies the parameter in a way that is visible after the procedure returns.