Stop

Stop is a language for defining software systems.

The goal of Stop is to serve as a software blueprint. It is a tool that allows developers to focus and communicate the goals of a system without specific programming language implementation. Stop defines the data model, states and transitions of a software system.

Editor

The official Stop web based editor features syntax highlighting and real time reference, transition and logic checking. Try writing sample Stop systems as you read the documentation below.

Roadmap

The language is just the start. The plan is to map a Stop definition directly to a running software system where state implementation can be written in a variety of programming languages.

Why is it called Stop?

Because Go is popular and it's not Go. It's Stop. Also, a key concept of the language is finding a stopping state.

Hello World!

Here is a Hello World! of a simple Stop file.

    start Hello {
        string whom
        -> Say
    }
    
    stop Say {
        string words
    }
        

This system satisfies the minimum requirement of at least one start and stopping state. There is one transition from the starting Hello state to the stopping state of Say. The Hello state would require an implementation that would transition only to the Say state with the correct arguments (in this case a single property of type string called words).

States

Stop revolves around one main type called a state. Everything in Stop is a kind of state.

The simplest version of a state looks like a basic data object. Every property is required and there is no concept of null. If a property should be empty it should contain the default value for the type.

    User {
        uint64 id
        string username
        string email
    }
        

A state can define transitions to other states.

    Router {
        Request request
        -> Login
        -> Authenticate
    }
        

A state can throw an error state and transition to it.

    UserNotFoundError {
        string message
    }

    Authenticate throws UserNotFoundError {
        string login
        string password
        -> Redirect
    }
        

A state can be asynchronous. Asynchronous states require a timeout to be defined. Timeouts require a transition to be defined in the event the call to this state times out.

    async CreatePost {
        Post post
        timeout 30 -> TimeoutError
        -> Redirect
    }
        

A state can also yield a single value and return it. Value states are utilized as dynamic properties.

    async GetUser <- User {
        uint64 user_id
        timeout 5 -> TimeoutError
    }

    Profile {
        uint64 user_id
        User user <- GetUser
        -> Render
    }
        

Properties

States can define scalar, reference, enumeration, collection and dynamic properties.

Scalar properties

Here is a list of the scalar property types that can be used:

Reference properties

A state can define a property with the type of another State. Here a User object has an address property of type Address.

    Address {
        string street
        string city
        string state
        string zip
    }

    User {
        uint64 id
        string username
        string email
        Address address
    }
        

Enumeration properties

Enumerations can be defined within a state. Here an enumeration role is defined and referenced as a property.

    User {
        enum Role {
            STANDARD
            MANAGER
            ADMIN
        }
        uint64 id
        string username
        string email
        Role role
    }
        

Collection properties

A property can also be defined as a collection of either scalar, enum or state types. Here the emails and addresses properties are collections.

    Address {
        string street
        string city
        string state
        string zip
    }

    User {
        uint64 id
        string username
        [string] emails
        [Address] addresses
    }
        

Dynamic properties

Dynamic properties are not required when transitioning to a state with them defined. These properties will be calculated at runtime.

They are defined like any other property but with a <- operator following by a reference to a value state that returns the same property type.

Here in the Profile state user_id would be a required property while the user property is dynamic. The user property will be retrieved by calling the asynchronous value state GetUser with the mapped user_id property. GetUser is responsible for returning a User object within a 5 second timeout. The Profile state is valid after it has gathered all of its required and dynamic properties successfully.

    async GetUser <- User throws UserNotFoundError {
        uint64 user_id
        timeout 5 -> TimeoutError
    }

    Profile {
        uint64 user_id
        User user <- GetUser
        -> Render
    }
        

Optional properties

A property can be made optional by prefixing the definition with the keyword optional. Otherwise properties default to being required.

Optional properties can be left undefined when building an instance of a State. Any Stop runtime implementation should be dynamically checking for optionality during state transition validation.

Use optionals sparingly. State implementations that rely on States with optionals will have to handle the ambiguity presented by properties that could be undefined.

In the example below a body property is optional and likely only used on POST requests.

    Request {
        enum Method {
            GET
            POST
            PUT
            DELETE
            OPTIONS
        }
        Method method
        string path
        optional string body
        [Header] headers
        [Parameter] parameters
    }
        

Transitions

Transitions are defined within a state with the -> operator following by a reference to defined state.

    Router {
        Request request
        -> Login
        -> Register
    }
        

A state with transitions implies a programming implementation. Another piece of code somewhere will decide how this transition takes place but the only possible transitions are to Login and Register. When the state decides to transition that programming implementation will be required to create valid Login and Register states with their required properties.

Starting States

A Stop system needs at least one start state. There can be multiple start states that identify entry points into the software system.

    start Router {
        Request request
        -> Login
        -> Register
    }
        

Stopping states

Every sequence of transitions must eventually end in a stop state. A Stop file is considered incorrect if any transition does not lead to a stop state.

    start Router {
        Request request
        -> Login
    }

    Login {
        -> Response
    }

    stop Response {
        uint32 status
        string content_type
        string body
    }
        

Asynchronous States

By default all states in Stop are treated as synchronous states. In order to designate a state is asynchronous the async keyword needs to proceed the state name.

A state cannot be asynchronous and considered a starting or stopping state. This means a system cannot start ot stop on an asynchronous state.

Asynchronous states require a timeout to be defined in seconds that is greater than 0. A transition must also be defined to handle the timeout occurring. On a timeout the system will halt and transition to the defined state.

An asynchronous state example:

    async CreatePost {
        Post post
        timeout 30 -> TimeoutError
        -> Redirect
    }
    

An asynchronous value state that can be used as a dynamic property:

    async GetUser <- User {
        uint64 user_id
        timeout 5 -> TimeoutError
    }
        

Errors

States can throw error states to transition to when something goes wrong. They work exactly like transitions just with a comma separated list of state references after throws. What happens after transitioning to an error state is up to you (just be sure it eventually finds a stopping state).

    RouteNotFoundError {
        string message
        -> Render
    }

    UnauthorizedError {
        string message
        -> Render
    }

    Router throws RouteNotFoundError, UnauthorizedError {
        Request request
        -> Login
        -> Register
        -> Dashboard
    }
        

About

Author

Kyle Shank

Source Code

Github

License

Stop is open source and licensed under the MIT License.