Skip to content

Commit 24abf6e

Browse files
authored
Merge pull request #81 from VariantSync/develop
Release 2.0
2 parents 3ef8441 + 0059cd7 commit 24abf6e

75 files changed

Lines changed: 1686 additions & 1417 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
*.#*
66
.dir-locals.el
77

8+
# emacs' agda mode
9+
src/agda2-mode*
10+
811
# build
912
src/cc
1013
src/Main

README.md

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,110 @@ This library formalizes all results in our paper:
2727
Additionally, our library comes with a small **demo**, and **tutorials** for getting to know the library and for formalizing your own variability languages (see "Tutorials" section below).
2828
When run in a terminal, our demo will show a translation roundtrip, showcasing the circle of compilers developed for identifying the map of variability languages (Section 5).
2929

30+
## Overview: What is Static Variability and What is Vatras?
31+
32+
Vatras is a library to study and compare meta-languages for specifying variability in source code and data.
33+
Some software systems are configurable _before_ they are compiled, i.e., statically.
34+
A common way example for implementing static variability is by conditional compilation, as for example possible with the C preprocessor.
35+
For instance, the following [code snippet from the Linux kernel](https://github.com/torvalds/linux/blob/e271ed52b344ac02d4581286961d0c40acc54c03/include/linux/console.h#L479-L486)
36+
37+
```C
38+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
39+
extern bool console_srcu_read_lock_is_held(void);
40+
#else
41+
static inline bool console_srcu_read_lock_is_held(void)
42+
{
43+
return 1;
44+
}
45+
#endif
46+
```
47+
48+
replaces the function `console_srcu_read_lock_is_held` with a default implementation in case a particular feature should be debugged.
49+
Essentially, the code snippet above does not denote a single `C` program but two `C` programs, each using one of two alternatives for the function `console_srcu_read_lock_is_held`.
50+
51+
To model and analyze static variability, researchers have formalized various formal languages, including formalisms for conditional compilation.
52+
For example, the _choice calculus_ is a small language to formalize conditional compilation in terms of a singly syntactic term, referred to as a _choice_.
53+
A choice `F ⟨ l , r ⟩` specifies two alternatives `l` and `r` for a feature or configuration option `F`.
54+
Encoding the example above in choice calculus yields
55+
56+
```
57+
CONFIG_DEBUG_LOCK_ALLOC ⟨
58+
extern bool console_srcu_read_lock_is_held(void);
59+
,
60+
static inline bool console_srcu_read_lock_is_held(void)
61+
{
62+
return 1;
63+
}
64+
65+
```
66+
67+
Apart from source code, static configuration processes emerge in many other areas, including our daily lives.
68+
For instance, some restaurants offer your to configure your meal.
69+
Sticking to the choice calculus, we may for example specify a configurable sandwich that _always_ has bread 🍞 and cheese, _maybe_ has salad 🥗 (expressed as a choice between Salad 🥗 and an empty value `ε`), _either_ has a meat 🍖 or falafel 🧆 patty, and has _any_ combination of mayonnaise 🥚 and ketchup 🍅 as follows:
70+
71+
```
72+
🍞-<
73+
Salad⟨ 🥗, ε ⟩,
74+
🧀,
75+
Patty⟨ 🍖, 🧆 ⟩,
76+
Sauce⟨ ε, 🥚, 🍅, 🍅🥚 ⟩
77+
>-
78+
```
79+
where the Y-brackets of the outer expression `🍞-< ... >-` denote that the ingredients go _within_ the bread (i.e., we build a tree where the ingredients are sub-expressions of bread).
80+
81+
The goal of Vatras is to formalize and _compare_ languages for static variabilty.
82+
To this end, we formalize the syntax and semantics of the choice calculus, some of its dialects, and many more formal languages for static variability.
83+
For instance, writing out the above sandwich expression in our Agda formalization of the choice calculus, closely resembles the original expressions (most boilerplate comes from explicit list syntax):
84+
85+
``` agda
86+
sandwich : CCC Feature ∞ Artifact
87+
sandwich =
88+
"🍞" -<
89+
"Salad" ⟨ leaf "🥗" ∷ leaf "ε" ∷ [] ⟩
90+
∷ leaf "🧀"
91+
∷ "Patty" ⟨ leaf "🍖" ∷ leaf "🧆" ∷ [] ⟩
92+
∷ "Sauce" ⟨ leaf "ε" ∷ leaf "🥚" ∷ leaf "🍅" ∷ leaf "🍅🥚" ∷ [] ⟩
93+
∷ []
94+
>-
95+
where
96+
leaf : String → CCC Feature ∞ Artifact
97+
leaf a = a -< [] >-
98+
```
99+
100+
We may configure our sandwich in terms of the semantics `⟦_⟧` for choice calculus.
101+
The semantics is a function takes a configuration as input to produce a variant.
102+
For our sandwich example, a configuration decides for each configuration option `Salad`, `Patty`, and `Sauce` which alternative to pick.
103+
A variant is a sandwich without any conditional elements left (i.e., a term without choices).
104+
From a configuration, we can derive the respective sandwich variant, and we can use Agda to prove that the semantics derive the variant we expect:
105+
106+
``` agda
107+
config : Feature → ℕ
108+
config "Salad" = 0
109+
config "Patty" = 1
110+
config "Sauce" = 2
111+
config _ = 0
112+
113+
config-makes-falafel-ketchup-sandwich :
114+
⟦ sandwich ⟧ config ≡
115+
"🍞" -<
116+
leaf "🥗"
117+
∷ leaf "🧀"
118+
∷ leaf "🧆"
119+
∷ leaf "🍅"
120+
∷ []
121+
>-
122+
config-makes-falafel-ketchup-sandwich = refl
123+
```
124+
125+
Vatras enables semantic comparisons of variability languages based on a meta-theory centered around the three fundamental yet unexplored properties of completeness, soundness, and expressiveness.
126+
Completeness serves as a lower bound (i.e., a language can express at least a given semantic domain),
127+
soundness serves as an upper bound (i.e., a language can express at most a given semantic domain),
128+
and expressiveness serves as a relative comparison (i.e., a language can express at least the semantic domain of another language).
129+
Proofs of these properties come as _encodings_ for completeness (i.e., a function that creates a variational expression from a set of variants), _enumerations_ for soundness (i.e., a function that enumerates all variants denoted by a variational expression), and _compilers_ between languages for expressiveness.
130+
Vatras includes a range of proofs of these properties for existing languages as explained in our respective paper.
131+
As a showcase, Vatras will show a roundtrip translation of the configurable sandwich specification above when you run it.
132+
Details on the features implemented in Vatras, including tutorials for integrating new languages, can be found in the **Reusability Guide** below.
133+
30134
## Kick-the-Tires
31135

32136
This section gives you a short "Getting Started" guide.
@@ -502,7 +606,8 @@ Executing `git submodule update --init` in the root of the repository should fix
502606
## Where does the library name 'Vatras' come from?
503607

504608
The name Vatras is (of course) an acronym, which stands for _VAriability language TRAnslationS_.
505-
Besides, Vatras is a water mage in the classic german RPG [Gothic II](https://almanach.worldofgothic.de/index.php/Vatras), who is praying to the god Adanos, who brings "some kind of equality" very loosely speaking.
609+
Besides, Vatras is a water mage in the classic german RPG [Gothic II](https://almanach.worldofgothic.de/index.php/Vatras), who stems from the city of Varant, which almost sounds like _Variant_.
610+
Vatras is praying to the god Adanos, who brings some kind of equality or balance loosely speaking.
506611

507612
[agda-badge-version-svg]: https://img.shields.io/badge/agda-v2.6.4.3-blue.svg
508613
[agda-badge-version-url]: https://github.com/agda/agda/releases/tag/v2.6.4.3

default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
},
1010
}:
1111
pkgs.agdaPackages.mkDerivation {
12-
version = "1.0";
12+
version = "2.0";
1313
pname = "Vatras";
1414
src = with pkgs.lib.fileset;
1515
toSource {

src/Vatras/Framework/Composition/FeatureAlgebra.lagda.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ record FeatureAlgebra {c} (I : Set c) (sum : Op₂ I) (𝟘 : I) : Set (suc c) w
180180
~-trans : Transitive _~_
181181
~-trans (i≤j , j≤i) (j≤k , k≤j) = ≤-trans i≤j j≤k , ≤-trans k≤j j≤i
182182
183-
-- From the above we can conclude that introduction equivalence is an equivalence relation (not mentioned in the paper).
183+
-- From the above we can conclude that introduction equivalence is an equivalence relation (not explicitly mentioned in the paper).
184184
~-IsEquivalence : IsEquivalence _~_
185185
~-IsEquivalence = record
186186
{ refl = ~-refl
@@ -207,10 +207,10 @@ record FeatureAlgebra {c} (I : Set c) (sum : Op₂ I) (𝟘 : I) : Set (suc c) w
207207
208208
{-
209209
Lemma 8:
210-
Introduction sum is commutative with respec to introduction equivalence.
210+
Introduction sum is commutative with respect to introduction equivalence.
211211
This means that on both sides, we have introductions that both "contain" the same introduction
212212
but maybe in a different order (so the results are not propositionally equal).
213-
Note that in general, introduction sum is not commutative with respect to proposition equality
213+
Note that in general, introduction sum is not commutative with respect to propositional equality
214214
(i.e., the syntax of the actual introduction type).
215215
-}
216216
quasi-commutativity : ∀ i₂ i₁ → i₂ ⊕ i₁ ~ i₁ ⊕ i₂

src/Vatras/Framework/Proof/ForFree.lagda.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ open import Vatras.Framework.VariabilityLanguage using (VariabilityLanguage)
1616
open import Vatras.Framework.Properties.Completeness V
1717
open import Vatras.Framework.Properties.Soundness V
1818
open import Vatras.Framework.Relation.Expressiveness V
19-
open import Vatras.Data.EqIndexedSet
19+
-- All properties here follow from transitivity and symmetry of ≅.
20+
open import Vatras.Data.EqIndexedSet using (≅-trans; ≅-sym)
2021
```
2122

2223
```agda

src/Vatras/Lang/2CC.lagda.md

Lines changed: 14 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,19 @@
33
## Module
44

55
```agda
6-
open import Vatras.Framework.Definitions
7-
module Vatras.Lang.2CC where
6+
open import Vatras.Framework.Definitions using (𝔽; 𝔸; atoms; 𝔼; ℂ)
7+
module Vatras.Lang.2CC (Dimension : 𝔽) where
88
```
99

1010
## Imports
1111

1212
```agda
13-
open import Data.Bool using (Bool; true; false; if_then_else_)
14-
open import Data.List
15-
using (List; []; _∷_; lookup)
16-
renaming (map to mapl)
17-
open import Data.Product using (_,_)
18-
open import Function using (id)
13+
open import Data.Bool using (Bool; if_then_else_)
14+
open import Data.List as List using (List)
1915
open import Size using (Size; ↑_; ∞)
2016
2117
open import Vatras.Framework.Variants as V using (Rose)
22-
open import Vatras.Framework.VariabilityLanguage
18+
open import Vatras.Framework.VariabilityLanguage using (𝔼-Semantics; VariabilityLanguage; ⟪_,_,_⟫)
2319
```
2420

2521
## Syntax
@@ -31,9 +27,9 @@ or a binary choice `D ⟨ l , r ⟩` between two sub-expressions `l` and `r`, wh
3127
to identify the choice upon configuration.
3228
Dimensions `D` can be of any given type `Dimension : 𝔽`.
3329
```agda
34-
data 2CC (Dimension : 𝔽) : Size → 𝔼 where
35-
_-<_>- : ∀ {i A} → atoms A → List (2CC Dimension i A) → 2CC Dimension (↑ i) A
36-
_⟨_,_⟩ : ∀ {i A} → Dimension → 2CC Dimension i A → 2CC Dimension i A → 2CC Dimension (↑ i) A
30+
data 2CC : Size → 𝔼 where
31+
_-<_>- : ∀ {i A} → atoms A → List (2CC i A) → 2CC (↑ i) A
32+
_⟨_,_⟩ : ∀ {i A} → Dimension → 2CC i A → 2CC i A → 2CC (↑ i) A
3733
```
3834

3935
## Semantics
@@ -47,175 +43,16 @@ We define `true` to mean choosing the left alternative and `false` to choose the
4743
Defining it the other way around is also possible but we have to pick one definition and stay consistent.
4844
We choose this order to follow the known _if c then a else b_ pattern where the evaluation of a condition _c_ to true means choosing the then-branch, which is the left one.
4945
```agda
50-
Configuration : (Dimension : 𝔽) →
51-
Configuration Dimension = Dimension → Bool
46+
Configuration : ℂ
47+
Configuration = Dimension → Bool
5248
53-
⟦_⟧ : ∀ {i : Size} {Dimension : 𝔽} → 𝔼-Semantics (Rose ∞) (Configuration Dimension) (2CC Dimension i)
54-
⟦ a -< cs >- ⟧ c = a V.-< mapl (λ e → ⟦ e ⟧ c) cs >-
49+
⟦_⟧ : ∀ {i : Size} → 𝔼-Semantics (Rose ∞) Configuration (2CC i)
50+
⟦ a -< cs >- ⟧ c = a V.-< List.map (λ e → ⟦ e ⟧ c) cs >-
5551
⟦ D ⟨ l , r ⟩ ⟧ c =
5652
if c D
5753
then ⟦ l ⟧ c
5854
else ⟦ r ⟧ c
5955
60-
2CCL : ∀ {i : Size} (Dimension : 𝔽) → VariabilityLanguage (Rose ∞)
61-
2CCL {i} Dimension = ⟪ 2CC Dimension i , Configuration Dimension , ⟦_⟧ ⟫
62-
```
63-
64-
In the following, we prove some interesting properties about binary choice calculus,
65-
known from the respective papers.
66-
67-
```agda
68-
module _ {Dimension : 𝔽} where
69-
```
70-
71-
## Properties
72-
73-
Some transformation rules:
74-
```agda
75-
open Data.List using ([_])
76-
open import Data.List.Properties using (map-∘; map-cong)
77-
open import Data.Nat using (ℕ)
78-
open import Data.Vec as Vec using (Vec; toList; zipWith)
79-
import Data.Vec.Properties as Vec
80-
import Vatras.Util.Vec as Vec
81-
82-
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl; _≗_)
83-
84-
module Properties where
85-
open import Vatras.Framework.Relation.Expression (Rose ∞)
86-
87-
module _ {A : 𝔸} where
88-
{-|
89-
Given a choice between two artifacts with the same atom 'a',
90-
we can factor out this atom 'a' outside of the choice because no matter
91-
how we configure the choice, the resulting expression will always have 'a'
92-
at the top.
93-
-}
94-
choice-factoring : ∀ {i} {D : Dimension} {a : atoms A} {n : ℕ}
95-
→ (xs ys : Vec (2CC Dimension i A) n)
96-
------------------------------------------------
97-
→ 2CCL Dimension ⊢
98-
D ⟨ a -< toList xs >- , a -< toList ys >- ⟩
99-
≣₁ a -< toList (zipWith (D ⟨_,_⟩) xs ys) >-
100-
choice-factoring {i} {D} {a} {n} xs ys c =
101-
⟦ D ⟨ a -< toList xs >- , a -< toList ys >- ⟩ ⟧ c
102-
≡⟨⟩
103-
(if c D then ⟦ a -< toList xs >- ⟧ c else ⟦ a -< toList ys >- ⟧ c)
104-
≡⟨ lemma (c D) ⟩
105-
a V.-< toList (zipWith (λ x y → if c D then ⟦ x ⟧ c else ⟦ y ⟧ c) xs ys) >-
106-
≡⟨⟩
107-
a V.-< toList (zipWith (λ x y → ⟦ D ⟨ x , y ⟩ ⟧ c) xs ys) >-
108-
≡⟨ Eq.cong (a V.-<_>-) (Eq.cong toList (Vec.map-zipWith (λ e → ⟦ e ⟧ c) (D ⟨_,_⟩) xs ys)) ⟨
109-
a V.-< toList (Vec.map (λ e → ⟦ e ⟧ c) (zipWith (D ⟨_,_⟩) xs ys)) >-
110-
≡⟨ Eq.cong (a V.-<_>-) (Vec.toList-map (λ e → ⟦ e ⟧ c) (zipWith (D ⟨_,_⟩) xs ys)) ⟩
111-
a V.-< mapl (λ e → ⟦ e ⟧ c) (toList (zipWith (D ⟨_,_⟩) xs ys)) >-
112-
≡⟨⟩
113-
⟦ a -< toList (zipWith (D ⟨_,_⟩) xs ys) >- ⟧ c
114-
115-
where
116-
open Eq.≡-Reasoning
117-
lemma : (b : Bool) →
118-
(if b then ⟦ a -< toList xs >- ⟧ c else ⟦ a -< toList ys >- ⟧ c)
119-
≡ a V.-< toList (zipWith (λ x y → if b then ⟦ x ⟧ c else ⟦ y ⟧ c) xs ys) >-
120-
lemma false =
121-
(if false then ⟦ a -< toList xs >- ⟧ c else ⟦ a -< toList ys >- ⟧ c)
122-
≡⟨⟩
123-
⟦ a -< toList ys >- ⟧ c
124-
≡⟨⟩
125-
a V.-< mapl (λ e → ⟦ e ⟧ c) (toList ys) >-
126-
≡⟨ Eq.cong (a V.-<_>-) (Vec.toList-map (λ e → ⟦ e ⟧ c) ys) ⟨
127-
a V.-< toList (Vec.map (λ y → ⟦ y ⟧ c) ys) >-
128-
≡⟨ Eq.cong (a V.-<_>-) (Eq.cong toList (Vec.zipWith₂ (λ y → ⟦ y ⟧ c) xs ys)) ⟨
129-
a V.-< toList (zipWith (λ x y → ⟦ y ⟧ c) xs ys) >-
130-
≡⟨⟩
131-
a V.-< toList (zipWith (λ x y → if false then ⟦ x ⟧ c else ⟦ y ⟧ c) xs ys) >-
132-
133-
lemma true =
134-
(if true then ⟦ a -< toList xs >- ⟧ c else ⟦ a -< toList ys >- ⟧ c)
135-
≡⟨⟩
136-
⟦ a -< toList xs >- ⟧ c
137-
≡⟨⟩
138-
a V.-< mapl (λ e → ⟦ e ⟧ c) (toList xs) >-
139-
≡⟨ Eq.cong (a V.-<_>-) (Vec.toList-map (λ e → ⟦ e ⟧ c) xs) ⟨
140-
a V.-< toList (Vec.map (λ x → ⟦ x ⟧ c) xs) >-
141-
≡⟨ Eq.cong (a V.-<_>-) (Eq.cong toList (Vec.zipWith₁ (λ x → ⟦ x ⟧ c) xs ys)) ⟨
142-
a V.-< toList (zipWith (λ x y → ⟦ x ⟧ c) xs ys) >-
143-
≡⟨⟩
144-
a V.-< toList (zipWith (λ x y → if true then ⟦ x ⟧ c else ⟦ y ⟧ c) xs ys) >-
145-
146-
147-
{-|
148-
A choice between two equal alternatives is no choice.
149-
No matter how we configure the choice, the result stays the same.
150-
-}
151-
choice-idempotency : ∀ {D} {e : 2CC Dimension ∞ A}
152-
---------------------------------
153-
→ 2CCL Dimension ⊢ D ⟨ e , e ⟩ ≣₁ e
154-
choice-idempotency {D} {e} c with c D
155-
... | false = refl
156-
... | true = refl
157-
158-
{-|
159-
If the left alternative of a choice is semantically equivalent
160-
to another expression l′, we can replace the left alternative with l′.
161-
-}
162-
choice-l-congruence : ∀ {i : Size} {D : Dimension} {l l′ r : 2CC Dimension i A}
163-
→ 2CCL Dimension ⊢ l ≣₁ l′
164-
---------------------------------------
165-
→ 2CCL Dimension ⊢ D ⟨ l , r ⟩ ≣₁ D ⟨ l′ , r ⟩
166-
choice-l-congruence {D = D} l≣l′ c with c D
167-
... | false = refl
168-
... | true = l≣l′ c
169-
170-
{-|
171-
If the right alternative of a choice is semantically equivalent
172-
to another expression r′, we can replace the right alternative with r′.
173-
-}
174-
choice-r-congruence : ∀ {i : Size} {D : Dimension} {l r r′ : 2CC Dimension i A}
175-
→ 2CCL Dimension ⊢ r ≣₁ r′
176-
---------------------------------------
177-
→ 2CCL Dimension ⊢ D ⟨ l , r ⟩ ≣₁ D ⟨ l , r′ ⟩
178-
choice-r-congruence {D = D} r≣r′ c with c D
179-
... | false = r≣r′ c
180-
... | true = refl
181-
```
182-
183-
## Utility
184-
185-
```agda
186-
open Data.List using (concatMap) renaming (_++_ to _++l_)
187-
188-
{-|
189-
Recursively, collect all dimensions used in a binary CC expression
190-
-}
191-
dims : ∀ {i : Size} {A : 𝔸} → 2CC Dimension i A → List Dimension
192-
dims (_ -< es >-) = concatMap dims es
193-
dims (D ⟨ l , r ⟩) = D ∷ (dims l ++l dims r)
194-
```
195-
196-
## Show
197-
198-
```agda
199-
open import Data.String as String using (String; _++_; intersperse)
200-
module Pretty (show-D : Dimension → String) where
201-
open import Vatras.Show.Lines
202-
203-
show : ∀ {i} → 2CC Dimension i (String , String._≟_) → String
204-
show (a -< [] >-) = a
205-
show (a -< es@(_ ∷ _) >-) = a ++ "-<" ++ (intersperse ", " (mapl show es)) ++ ">-"
206-
show (D ⟨ l , r ⟩) = show-D D ++ "⟨" ++ (show l) ++ ", " ++ (show r) ++ "⟩"
207-
208-
pretty : ∀ {i : Size} → 2CC Dimension i (String , String._≟_) → Lines
209-
pretty (a -< [] >-) = > a
210-
pretty (a -< es@(_ ∷ _) >-) = do
211-
> a ++ "-<"
212-
indent 2 do
213-
intersperseCommas (mapl pretty es)
214-
> ">-"
215-
pretty (D ⟨ l , r ⟩) = do
216-
> show-D D ++ "⟨"
217-
indent 2 do
218-
appendToLastLine "," (pretty l)
219-
pretty r
220-
> "⟩"
56+
2CCL : ∀ {i : Size} → VariabilityLanguage (Rose ∞)
57+
2CCL {i} = ⟪ 2CC i , Configuration , ⟦_⟧ ⟫
22158
```

0 commit comments

Comments
 (0)