-
Notifications
You must be signed in to change notification settings - Fork 1
Home
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:
Which is going to be used as an example during the documentation.
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 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 }
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.
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 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
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.