Skip to content
This repository has been archived by the owner on Oct 16, 2023. It is now read-only.
pabpazjim edited this page Sep 28, 2021 · 21 revisions

Universal Variability Language Documentation

Introduction

This wiki aims to be a comprehensive guide for the understanding and usage of Universal Variability Language (UVL). A description of the structure and syntax of the language will be given, with further explanations and examples.

imports
    FileSystem as fs
features
    Server { abstract }
        mandatory
            FileSystem
                or // with cardinality : [1..*]
                    NTFS
                    APFS
                    EXT4
            OperatingSystem { abstract }
                alternative
                    Windows
                    macOS
                    Debian
        optional
            Logging {
            default ,
            log_level " warn " // Feature Attribute
        }
constraints
    Windows => NTFS
    macOS => APFS

This UVL file defines the model represented by this diagram:

FM

Which is going to be used as an example during the documentation.

Indentation and blocks.

As the example shows, the language presents a Python-like indentation structure. We are using tabs (preceded by a line break) to define a new indentation block. If we look at the "features" word, we can see the feature "Server" following it with a line break and a tab, which is the start of a new indentation block. After this, there is a new indentation block consisting of both the words "mandatory" and "optional" as they are followed by the same previous word in the same indentation level.

An UVL file will consist of three main blocks: imports, features and constraints. Each one has to be opened with its respective word in the first indentation level (with no preceding tabs). The features block is mandatory and the imports and constraints blocks are optional. In any case, they have to be disposed in this order: imports, features and constraints.

It is important to mention that the language is sensitive to tabs as they define the indenation levels, but not to spaces, line breaks or carriage returns.

Features

Features block is the core part of the UVL file as it defines the features and its relations, while also being the one with the most complex grammar.

As it has been mentioned before, we will open this block with the reserved word "features". An only root feature will follow the features word in the next indentation level.

This piece of the previous example shows that and, despite it being a single feature, its grammar is the same as any other feature, so we will see how any feature can be defined:

features
    Server { abstract }

Feature grammar

Every feature consists of a name and an optional set of attributes.

A feature name will always start by an upper or lower case letter, followed by any other letter, number or underscore:

// any of these are correct UVL feature definitions.
Server
server
ubuntu_server
ubuntu_server_v2

In addition, a feature name can also consist of a set of words (being a word a piece of text which matches the grammar defined above), separated by dots:

// any of these are also correct UVL feature definitions.
fs.FileSystem
fs.FileSystem.NTFS

However, this kind of feature anotation is used to introduce imported features, which will be explained later.

Now that we are able to name features, we will see how their attributes can be defined. The attributes set will always be written inside a curly bracket "{}" block after the feature name. This block can contain zero, one, or more attributes separated by commas:

Server {} // Empty set, same as "Server"
Server {abstract}
Server {abstract, default}

In addition, each attribute actually consists of a mandatory key (which we have already used in the previous example) and an optional value. The value will always follow the key inside a double quotation mark block:

Logging {
default ,
log_level " warn "
}

This feature, which is part of the first example, shows a set of two attributes, one with value and another without it. Additionally, it shows how the language's lack of line break sensibility allows us to display the attributes a much more readable way.

Knowing this, we will be able to define any feature in a UVL file.

Relation structure

Now that we know the features grammar in the UVL language, we will learn the structure the whole feature block follows. In order to do that, we need to tell two different kind of words apart: features (which we already know) and relation words.

Relation words are words that define relations between features. In UVL, any of these words: alternative, or, mandatory, optional are relation words. In addition, custom cardinalities can also be used, described as [a..b] or [b], where a is the minimum cardinality and b the maximum. Any word following this structure is also considered a relation word.

Knowing this, the feature block will follow an iterative structure. First, it will always start with a root feature. Then, it will be followed by a set of relation words, with each one containing containing a set of features. Any of these features can contain a set of relation words, and so on. We will break down the first example for a better understanding of the structure.

This shows just the root feature:

features
    Server { abstract }

Now, we see the relation words which follow the root feature. However, this makes no sense as no feature is contained inside the relation words:

features
    Server { abstract }
        mandatory
        optional

Every feature is an indenation level deeper than the relation word. However, the features are all children of Server and what the relation words tell is which ones are mandatory and which ones are optional:

features
    Server { abstract }
        mandatory
            FileSystem
            OperatingSystem
        optional
            Logging

// attributes removed for readability

Now, inside each FileSystem and OperatingSystem we introduce a relation word, with each one being followed by a set of features. These two examples show the same FM, one using keywords, and other using custom cardinalities, as both are considered relationship words.

features
    Server { abstract }
        mandatory
            FileSystem
                or
                    NTFS
                    APFS
                    EXT4
            OperatingSystem
                alternative
                    Windows
                    macOS
                    Debian
        optional
            Logging
features
    Server { abstract }
        mandatory
            FileSystem
                [1..*]
                    NTFS
                    APFS
                    EXT4
            OperatingSystem
                [1]
                    Windows
                    macOS
                    Debian
        optional
            Logging

Constraints

Constraints in UVL are expressed as propositional formulas. The constraint block itself has all its constraints one indentation level after the "constraints" word. Any constraint is specified by its feature name(s) and operator.

This part of the first example shows two implication constraints between model features.

constraints
    Windows => NTFS
    macOS => APFS

Propositional operators supported by UVL are negation, conjunction, disjunction, implication and equivalence, which can be specified as follows:

!Windows // Negation
Windows & NTFS // Conjunction
Windows | NTFS // Disjunction
Windows => NTFS // Implication
Windows <=> NTFS // Equivalence

Imports

As conjunctions, every import is placed one indentation level after the "imports" word. Any import consists of a word, which follows the same grammar as feature words, and an optional "as" clause followed by another word. The following examples show some practical cases:

imports
    Server // Import the whole Server.UVL file FM, with Server as reference name
    Server as srv // Same as before, changing reference name to sys
    Server.FileSystem // Import the FileSystem subpart of the Server FM, with Server.FileSystem as reference name
    Server.FileSystem as fs // Same as before, changing reference name to fs

For each FM imported, its reference name is the word to be used in the features block for the imported model to be placed inside the main model.