execution context (e.g., managing conditional breakpoints logic and manually editing
values). As an added benefit, the debugger can be safely separated from the tool man-
aging the execution itself, meaning that an execution engine could be told to no longer
loop through the steps and instead give control to a debugger at any point, while also
allowing a REPL to run code snippets for e.g., exploratory programming and omniscient
debugging purposes.

In order to prove the usability of the protocol in actual scenarios, the next section
will describe several operational semantics formalizations and implementations that can
expose the necessary services.

6.3 Implementation & Evaluation

6.3.1 Operational Semantics Formalization

Considering the minimalistic nature of the expressed protocol, we are aware that it
can be implemented in a lot of different ways. As of now, we do not provide guidelines
to obtain the “best” implementation. Each DSL is different, and language engineers
are various and used to different technologies and styles of semantics implementations.
Evaluating the best implementation for a given DSL is not part of the scope of this thesis,
so instead this section describes formally multiple possibilities. One of them, “Procedural
style”, also comes with the specifications of a generative approach that can be applied to
existing operational semantics, but this does not mean that we want to enforce this one in
particular. The generative approach should be seen mainly as an applicability evaluation,
since we consider that implementing the interface should be a design decision above all
else.

In [15], a formal model is developed that characterizes interpreters that naturally
exhibit REPL behavior. In this model, interpreters are transition functions over configura-
tions – deterministic transition relations in the style of Plotkin’s Structural Operational
Semantics (SOS) [64]. The notion of a sequential language is defined, capturing the
class of languages<fnref n="4" /> in which a sequence of programs is itself a valid program such
that the effect of the composite program is that of the individual programs executed
one-by-one in order. This behavior naturally corresponds to the behavior of a REPL, in
which a larger program is developed by repeatedly submitting program fragments. In

<footnote n="4">4. Not necessarily equal to the class of languages that execute non-concurrently.</footnote>
addition, the paper proposed a methodology in which, in order to obtain a REPL for some language $L$, the language $L$ is extended to a sequential variant of $L$. The method involves selecting the ‘entry points’ of the language $L$ – the syntactic categories of which program fragments should be accepted at the REPL’s prompt – and defining the syntactic category of “phrases” as the union of the entry points. An interpreter (or operational semantics) for $L$ can then be reused to define an interpreter (or operational semantics) for the phrases of $L$. The interpreter for phrases should express the effects of phrases as modifications to a given configuration (representing runtime state). To obtain a REPL with the desired behavior, any effects of a phrase that affect subsequent phrases should manifest as a modification to the input configuration (e.g., introducing new bindings in an environment or assignments in a store). The result is an extended language $L'$ with phrases as programs and an interpreter that can be used as the basis of a REPL. Here we show that if the interpreter for $L$ is a stepwise interpreter, executing or evaluating program fragments step-by-step, then $L'$ automatically gives rise to an $L''$ supporting the basic features of debugging on top of REPL-style programming.

A stepwise interpreter is defined as follows.

**Definition 6.3.1.** Given a set of configurations $\Gamma$ and a set of computations $C$, a stepwise interpreter is a function $\rightsquigarrow : C \times \Gamma \to C^{\text{done}} \times \Gamma$, with $C^{\text{done}} = C \cup \{\text{done}\}$. The iterative closure of $\rightsquigarrow$ is the function $\leftarrow\to : C^{\text{done}} \times \Gamma \to \Gamma$ defined as:

$$ \langle \text{done}, \gamma \rangle \leftarrow\to \gamma \qquad (6.1) $$

$$ \frac{\langle c_1, \gamma_1 \rangle \rightsquigarrow \langle c_2, \gamma_2 \rangle \quad \langle c_2, \gamma_2 \rangle \leftarrow\to \gamma_3}{\langle c_1, \gamma_1 \rangle \leftarrow\to \gamma_3} \qquad (6.2) $$

The iterative closure $\leftarrow\to$ captures the full<fnref n="5" /> evaluation of a computation where $\rightsquigarrow$ captures step-by-step evaluation.

In [15], a language is considered to define a set of phrases $P$, a set of configurations $\Gamma$, an ‘initial’ configuration $\gamma^0 \in \Gamma$ and a (definitional) interpreter in the form of a family of functions $I$, assigning to each $p \in P$ a function $I_p : \Gamma \to \Gamma$. Consider that our hypothetical language $L$ has $m$ syntactic categories, defined via grammar/production rules, with $S_i$ denoting the set of sentences generated by the $i$-th category for each $1 \le i \le m$ (making

<footnote n="5">5. For simplicity, we ignore that computations may diverge, in which case the iterative closure is not well-defined.</footnote>
no assumptions about whether the sentences are strings, parse trees or otherwise). If the language is extended to the sequential variant $L'$ according to the method proposed in [15], then the categories can be ordered such that there is a $1 \le n \le m$ for which holds that the first $n$ categories are the entry points of the language. That is, the syntax of phrases is defined by the following abstract syntax definition with $s \in S_1 \cup \dots \cup S_n$:

$$p \in P ::= s \mid p_1; p_2$$

(The alternate $p_1$; $p_2$ denotes the sequential composition of phrases, following the methodology of [15].)

Next, we are going to assume the existence of a function $sem: S \to C$ that converts sentences into computations expressing the semantics of sentences and a stepwise interpreter for evaluating these computations. Under these assumptions, it is possible to extend $L'$ with the core debugging constructs step, finish, and debug(s). The syntactic part of this extension is as follows, defining the set of phrases $P'$:

$$p \in P' ::= s \mid p_1; p_2 \mid \mathbf{debug}(s) \mid \mathbf{step} \mid \mathbf{finish}$$

The extended language $L''$ is then given by the structure $\langle P', \Gamma \times C^{\text{done}}, \langle \gamma^0, \text{done} \rangle, I \rangle$, with the definitional interpreter $I_p$ (for all $p \in P'$) defined by the following equations:

$$I_s(\langle \gamma_1, c \rangle) = \langle \gamma_2, \mathbf{done} \rangle \quad \mathbf{where} \quad \langle sem(s), \gamma_1 \rangle \dashrightarrow \gamma_2 \qquad (6.3)$$

$$I_{p_1;p_2}(\langle \gamma_1, c_1 \rangle) = I_{p_2}(I_{p_1}(\langle \gamma_1, c_1 \rangle)) \qquad (6.4)$$

$$I_{\text{debug}(s)}(\langle \gamma_1, c_1 \rangle) = \langle \gamma_1, sem(s) \rangle \qquad (6.5)$$

$$I_{\text{step}}(\langle \gamma_1, c_1 \rangle) = \langle \gamma_2, c_2 \rangle \quad \mathbf{where} \quad \langle c_1, \gamma_1 \rangle \rightsquigarrow \langle c_2, \gamma_2 \rangle \qquad (6.6)$$

$$I_{\text{finish}}(\langle \gamma_1, c_1 \rangle) = \langle \gamma_2, \mathbf{done} \rangle \quad \mathbf{where} \quad \langle c_1, \gamma_1 \rangle \dashrightarrow \gamma_2 \qquad (6.7)$$

The main intuition behind these definitions is that the extended language $L''$ has an additional component in its configurations to keep track of (possibly done or otherwise intermediate) computations. In other words, the evaluation of a phrase can be performed via more than one step, with remaining steps represented by the computation component of the configuration (if any). The computation component corresponds to the step data structure described in the previous section, with the **debug** phrase serving a similar purpose as the **interpret** message of our protocol, readying a program/sentence for future stepwise execution. In the formalizations of the upcoming subsections, the computation
component is a stack of procedure calls, a continuation function or a program term as used in Plotkin's SOS.

Via the approach described here, intermediate computations are also reflected in the *execution graph* underlying the *exploring interpreter* proposed in [15] for the purposes of exploratory programming. An exploring interpreter is a bookkeeping device on top of a definitional interpreter (as defined in [15]) that records the configurations reached by executing phrases with the definitional interpreter in an execution graph. By combining these approaches, omniscient debugging [18, 53] is achieved. Strategies for efficient omniscient debugging with an exploring interpreter are to be investigated in future work.

The connection between the implementations discussed in Section 6.3.2 and the theory developed here is demonstrated next by discussing both procedural (stack-based) stepwise interpreters, functional (continuation-based) stepwise interpreters, and interpreters derived from SOS specifications.

## Procedural style

An operational semantics can be given as a collection of procedures (or methods in object-oriented languages) with each procedure expressing the effects of evaluating a code fragment of a particular syntactic category given some (implicit or explicit) context. The MiniJava description of Section 6.3.2 provides an example of such an operational semantics in the ALE meta-language. Executing a program corresponds to calling one of these procedures (depending on the syntactic category to which the program belongs), which may then call further procedures in a mutually-recursive fashion. Such an operational semantics can be explained as an instance of a stepwise interpreter by revealing the call-stack handling the procedure calls and handling all instructions in a procedure's body as if they were procedure calls as well. This is the approach taken in Section 6.3.2 and formalized in the subsequent paragraphs.

In the formalization of the approach, the function *sem* assigns to every sentence *s*, the stack of procedure calls that demand execution in order to evaluate *s*, with all necessary information propagated as part of the context between procedure calls. The translation procedure described in Section 6.3.2 thus forms the basis of *sem*. If for some hypothetical language the set of possible procedure calls is *P* and the context is captured by the set of configurations Γ, then we can define a stepwise interpreter by taking sequences of procedure calls as the computations of the stepwise interpreter, i.e., *C* = *P*<sup>+</sup>, *done* represents the empty sequence, and ↛<sub>STACK</sub> is defined as an instance of ↛ as follows
(with $\rho_i \in \mathcal{P}$ and ‘[‘ and ‘]‘ delimiting sequences):

$$ \langle [\rho_1, \dots, \rho_k], \gamma_1 \rangle \rightsquigarrow \mathop{\text{STACK}} \langle s \cdot [\rho_2, \dots, c_k], \gamma_2 \rangle \qquad (6.8) $$
$$ \textbf{where} \quad \langle \gamma_2, s \rangle = \text{exec}(\rho_1, \gamma_1) $$

The situation where $s \cdot [\rho_2, \dots, \rho_k]$ is the empty stack (i.e., the computation is done) arises when $k = 1$ and the procedure call $\rho_1$ does not add new elements to the stack ($s$ is empty). The situation where $s \cdot [\rho_2, \dots, \rho_k]$ is the empty stack arises when $k = 1$ and the procedure call $\rho_1$ does not add new elements to the stack (i.e., $s$ is the empty stack). The relation $\rightarrow \mathop{\text{STACK}}$, derived from $\rightsquigarrow \mathop{\text{STACK}}$ through equations 6.1 and 6.2, is operationalized by the following (purely functional) pseudocode:

1 loop stack,context) {
2 if (empty stack) {
3 return context;
4 } else {
5 let (c,stack') = pop (stack);
6 let (context',stack') = exec(c,context);
7 return loop (stack' ++ stack',context');
8 }
9 }

The implementation described in Section 6.3.2 demonstrates how a procedural operational semantics (in ALE) can be transformed into stack-based, stepwise interpreter. The transformation adds specific types of stack-elements that enable user-control over whether a procedure call halts the current execution and groups certain instructions together to reduce stack activity for efficiency.

## Continuation-passing style

An operational semantics can also be given as a collection of (pure) functions in continuation-passing style. In this style, functions receive an additional ‘continuation function’ as an argument to be called with a return value ‘at the end’ of a computational step, rather than actually returning the value. The continuation function of a called function thus explicates the next step of the computation following the called function. Continuation-passing style is commonly employed in compiler optimization steps to reduce stack activity through tail recursion. However, it can also be used as a (functional)
alternative to explicit stack-handling, as has been done in functional implementations of generalized parsing [41, 38, 13]. Similarly, the continuation-passing style can be used to define a stepwise interpreter, reminiscent of the procedural, stack-based, solution discussed previously.

In this approach, a continuation function is a function $k$ that given a configuration returns a configuration and either a continuation function or otherwise done. A continuation function plays the role of ‘computation’ in a stepwise interpreter and is (recursively) defined as yielding the subsequent computation to be performed (if any), i.e., $C$ is the set of functions $k: \Gamma \to \Gamma \times C_{\text{done}}$. The relation $\rightsquigarrow_{\text{CPS}}$ defines a stepwise interpreter for continuation-based operational semantics.

$$ \langle k_1, \gamma_1 \rangle \rightsquigarrow_{\text{CPS}} \langle k_2, \gamma_2 \rangle \quad \text{where} \quad \langle \gamma_2, k_2 \rangle = k_1(\gamma) \qquad (6.9) $$

Figure 6.1 shows (a simplified version of) the QL interpreter discussed further in Section 6.3.2 in which stepAll operationalizes the relation $\rightarrow_{\text{CPS}}$ derived from $\rightsquigarrow_{\text{CPS}}$. The function stepAll is called with the current program (Form), user input inp and the initial environment. The step function (not shown) evaluates the form to produce the initial configuration, which, if not done immediately, contains the context ctx and a continuation function of type $\kappa$. As such, step implements a combination of sem (turning a form into a continuation function) and a single transition (step) via $\rightsquigarrow_{\text{CPS}}$. The while-loop then repeatedly calls consecutive continuations until the result is a done configuration. The result of stepAll is the final context.

Since QL programs represent interactive forms, the actual implementation (see Section 6.3.2) runs in the event-loop of the UI, where calling of the step function is managed by the breakpoints and step/continue actions of the user.

## Small-step SOS style

An operational semantics can also be given as a small-step SOS specification [64] in which a collection of logical inference rules defines a transition relation $\to$. In a typical SOS specification, the transition relation is over structures of the form $\langle p, e_1, \dots, e_n \rangle$, with $p$ the program term under evaluation and $e_1, \dots, e_n$ auxiliary semantic entities (such as environments, stores, control signals) that provide context to the evaluation of $p$. The transition relation $\to$ captures the (small) steps via which the program term evaluates to either a term on which further steps can be taken, a fully evaluated term (often a
1 data Conf = conf(Ctx ctx, K cont) | done(Ctx ctx);
2
3 Ctx stepAll(Form f, Input inp, Env env) {
4 Conf c = step(f, inp, env);
5 while (! (c is done)) {
6 c = c.cont inp, c.ctxt);
7 }
8 return c.ctx;
9 }

Figure 6.1 – Executing a QL form f for user input inp in environment env by sequentially executing all steps.

value) or a stuck term (no further steps due to unexpected or undesireable behavior).
If the specification is deterministic, then for every combination of program term and
semantic entities, there is at most one transition, i.e. the transition relation is a (partial)
function.

Under these assumptions, an arbitrary SOS specification giving rise to $\rightarrow$ defines a stepwise interpreter as follows:

$$
\langle p, \langle e_1, \dots, e_n \rangle \rangle \rightsquigarrow_{\text{SOS}} \langle p', \langle e'_1, \dots, e'_n \rangle \rangle \quad \text{where} \tag{6.10}
$$

$$
\langle p, e_1, \dots, e_n \rangle \rightarrow \langle p', e'_1, \dots, e'_n \rangle
$$

$$
\langle p, \langle e_1, \dots, e_n \rangle \rangle \rightsquigarrow_{\text{SOS}} \langle \text{done}, \langle e_1, \dots, e_n \rangle \rangle \quad \text{otherwise} \tag{6.11}
$$

For practical reasons it may be desirable to make a difference between stuck program
terms and fully evaluated program terms. This can be achieved by syntactically defining
the notion of fully evaluated terms (or values) as part of the specification. Alternatively,
(attempted) transitions to (or from) stuck terms can be specified to raise errors.

In the component-based semantics approach of [12], a library of reusable fundamen-
tal constructs (funcons) is defined to reduce the effort of providing formal operational
semantics to programming languages. Both the funcons and the object language are
defined in the meta-language CBS. The funcons-tools project [14] implements a frame-
work in which so-called ‘micro-interpreters’ implement the behavior of individual funcons
having been generated from their definition written in a modular variant of SOS within
CBS. Applying the ideas expressed formally in this section, the funcons-tools frame-
work was easily extended to support both incremental (REPL-style) execution of funcon
terms and stepwise debugging. The extension of the original interpreter involved in
the order of 50-150 lines of Haskell code, most of which are related to the interactions
between the REPL and its user, e.g. reading input, providing feedback in the form of
output and by describing the meta-commands under 'help'.

**6.3.2 Languages Implementations**

This section presents two language implementations that expose the services requires
for the protocol, each based on one of the approaches formalized in Section 6.3.1. The
two follow different strategies, with the first one following a generative approach to
respect the protocol, and the second one being implemented from the start with protocol
support in mind.

Generated Stack-based Semantics

Here we evaluate the support of the proposed protocol through a generative approach
able to transform existing operational semantics written in ALE<fnref n="6" /> into a procedural, stack-
based, stepwise interpreter, following the formalization defined in Section 6.3.1.

The supported semantics are of the same nature as the ones used in [39] to generate
REPLs from existing DSL specifications:

- operational semantics written following a pure interpreter pattern in an imperative
  action language,

- and operations corresponding to observable execution steps explicitly annotated.

Such a definition can have multiple observable steps called in the same operation
body, which need to be separated in the execution stack. So the general idea is to *cut*
operation bodies into smaller operations of three different types:

- a **big-step-start** is an operation that will directly execute a single operation annotated as an observable step,

- a **big-step-end** serves as an indicator that a started step has ended and can also be
used to obtain return values following the start call,

- a **small-step** defines every other operation of the operational semantics that is not
an observable step.

<footnote n="6">6. https://gemoc.org/ale-lang/</footnote>
Since we are cutting operation bodies, we need to explicitly define their context and
handle it externally. So additions to the generated semantics include a new runtime class
“Context” for every cut operation, as well as a context instantiation method.

Figure 6.2 illustrates this process using the operator “+” defined as part of the
*MiniJava* (cf. Section 6.1) ALE semantics:

- The **eval** method of class **Plus** is annotated as an observable step, but more than that, two other step methods are called in its body: **left.eval()** and **right.eval()**. As such, it is necessary to cut the method body around these calls and re-implement the normal execution flow through the execution stack.

- **Plus_Eval_CONTEXT** is created to store the context of the cut method. It consists of both the parameters of the method and the variable definitions in its body. The method **newContext** can instantiate this new class and initialize the values for the previous parameters (in this case, **s**).

- Every reference to the parameters and variables definitions are replaced with references to the context.

- The items pushed in the execution stack are typed as big steps for the calls to **eval**, and small steps for the other inner calls that are not observable.

- Managing operations with return values (such as **eval**) requires accessing the context of this operation after it has finished executing. This is why the contexts instantiated in **eval_1** and **eval_3** are also stored in **c** and accessed in the “big-step-end” methods.

In the case of conditionals, such as a traditional if-then-else structural statement with
bodies that are blocks of statements, the same cutting needs to be done both around
the complete conditional, and around the step calls in the bodies. The reason is that,
just like with a call step, we have to make sure that the statements pre-conditional
and post-conditional are pushed to the stack to keep the expected control flow. If the
step call is in the expression of the conditional, it needs to be extracted with its value
stored in the context of the current method, and the corresponding big-step-end needs
to fetch this value, test it and push on top of the stack a small-step corresponding to
the body to execute. It is not possible to keep loop constructs with this approach, so the
transformation rewrites them using conditionals and recursive functions.

This whole process is generalizable to any operational semantics written in ALE and
using step annotations, by recursively cutting any method calling a step, then any method
calling a method calling a step, etc.

The execution stack, as shown in Figure 6.3, manages execution items that contain:

- **target**, the target of the original operation,

- **operationName**, the name (post cutting) of the operation to execute,

- **context**, the runtime context corresponding to the operation,

- **type**, the type of operation as defined earlier.

This requires a method lookup mechanism for every target that will end up being pushed in this stack. In our example, we automatically added a method `executeOperationFromName` that takes care of executing the right part of cut operations from their name post cutting.

With this, it is possible to define an operation in the interpreter to manage the execution of a big-step, as shown in Figure 6.4. This operation will start by popping an execution item from the stack and execute it. Then the behavior depends on the type of the execution item currently at the top of the stack: there is a need to execute every small-step until the next big-step, so small-steps are simply run inside a loop; if an operation is a big-step-end, it will also be executed and the environment notified that a step has finished; if the stack is empty, then the environment is notified that the execution is finished.

Figure 6.5 shows a current prototype of a notebook leveraging the protocol to offer a generic debugging framework. As of now, only stepping through cells and displaying the stack of the current cell are available. We can see that it is possible to run cells in any order, even when the debugger is paused on another cell (in this case, the 6th one is run while the 5th one is being debugged). For the REPL, every executed cell offers an output listing the changes made in the context, even if it is still quite naive and would require to be specialized with the concepts of the language.

## QL: a DSL Questionnaires

QL is a simple DSL for specifying interactive questionnaires, supporting data entry, computed values, and conditional logic. An example execution of a prototype IDE for QL is shown in Figure 6.6. The left shows a debugger view ("State") with widgets for each field of the questionnaire, affordances for setting break points and stepping through the execution. The area below the debugger view ("Application") shows the actual running questionnaire. The middle shows an editor with an example QL program, inspired by a
```java
open class Plus {
    @step
    def Integer eval(State s) {
        Integer leftVal := self.left.eval(s);
        Integer rightVal := self.right.eval(s);
        Integer resultVal := Integer.create();
        resultVal.intVal := leftVal.intVal + rightVal.intVal;
        result := resultVal;
    }
}
```

```java
open class Plus {
    def Plus_Eval Contex newContext(State s) {
        Plus_Eval Contex c := Plus_Eval Contex.create();
        c.s := s;
        result := c;
    }

    def void eval_1(ExecutionStack s, Context c) {
        Context newContext := self.left.newContext(c.s);
        c.newContext := newContext;
        s.push(self, 'eval_2', c, 'big-step-end');
        s.push(self.left, 'eval_1', newContext, 'big-step-start');
    }

    def void eval_2(ExecutionStack s, Context c) {
        c.leftVal := c.newContext.result;
        s.push(self, 'eval_3', c, 'small-step');
    }

    def void eval_3(ExecutionStack s, Context c) {
        Context newContext := self.right.newContext(c.s);
        c.newContext := newContext;
        s.push(self, 'eval_4', c, 'big-step-end');
        s.push(self.right, 'eval_1', newContext, 'big-step-start');
    }

    def void eval_4(ExecutionStack s, Context c) {
        c.rightVal := c.newContext.result;
        s.push(self, 'eval_5', c, 'small-step');
    }

    def void eval_5(ExecutionStack s, Context c) {
        c.resultVal := Integer.create();
        c.resultVal.intVal := c.leftVal.intVal + c.rightVal.intVal;
        c.result := resultVal;
    }

    class Plus_Eval Context extends Context {
        State s;
        Integer leftVal;
        Integer rightVal;
        Integer resultVal;
        Integer result;
        Context newContext;
    }
}
```

<caption>Figure 6.2 – Example of Operation Cutting for an Existing Plus Binary Operator</caption>
<figure><img src="image_29.png" /><figcaption>Figure 6.3 – Execution Stack Implementation</figcaption></figure>
<figure><img src="image_30.png" /><figcaption>Figure 6.4 – Big-Step Loop Execution</figcaption></figure>

<figure><img src="image_31.png" /><figcaption>Figure 6.5 – Prototype Generic Notebook with Debugger (Running MiniJava)</figcaption></figure>
tax filing application. Finally, the right shows a REPL for QL as sequential, numbered cells.

The REPL allows developers to enter commands, e.g., for evaluating expressions (1), updating fields (2), or navigating a debug session (4–11). Moreover, edit actions in the center are reflected in the REPL as commands as well, updating the semantic representation of the running application (3) [75, 70], in this case changing the label of the *privateDebt* question. This latter feature supports live programming: the running questionnaire dynamically adapts to source changes without restarting.

The semantics of QL dictates a spreadsheet-like evaluation model: after every interaction of the user with the questionnaire (or modifying the run-time state in the debugger view or REPL), the conditions and values of the computed questions (e.g., *valueResidue* are recomputed in a fixpoint loop. This is required because QL supports “use before define”: the value of a question can be referenced before the question is defined in the questionnaire. This is the reason that the debugger halts at the *valueResidue* breakpoint twice (cells 8 and 10).

QL is originally implemented as a definitional (big-step) interpreter. However, to support pausing the execution, the fixpoint and conditional logic have been converted into continuation-passing style as described in Section 6.3.1. Unlike the case-study of Section 6.3.2, the interpreter was not automatically derived from the original direct-style interpreter of QL, although the CPS interpreter reuses the evaluator of QL expression sub-language.

The key point of this demonstration is that all interaction with either debugger, code, or running application are reflected and recorded as commands in the REPL. As a result, the REPL is a syntactic and historic representation of interacting with the generic execution protocol.

The QL interpreter complies with the basic protocol of Section 6.2.1, restricted to the part that does not involve call-backs. The basic building blocks are **interpret**, **step**, **read**, and **write**. The first two enable full program evaluation (the running questionnaire, always on in this case) and fine-grained stepping through the evaluation; breakpoints and continue are implemented on top of **step**. The latter two requests deal with state modification, either via the debugger view, or the questionnaire itself.

Furthermore, because at each point the internal data structures (state vector, source code, continuations, etc.) are saved, the REPL becomes a vehicle for “undo” (the button with the up-arrow), essentially integrating versioning and back-in-time debugging in a
unified framework. We leave it as future work to investigate techniques to implement
this behavior efficiently in order to scale to bigger and more realistic languages.

These two implementations showcase how a language designer can benefit from
implementing, at least partially, the proposed protocol to provide an interactive envi-
ronment with support for debugging. Even if the shown environments may not fully
support some real-life scenarios, providing program execution, a REPL interpreter, and
debugging facilities already covers a significant portion of programming activity. Future
works still need to take into account more advanced execution tools, and study how they
would interact with the protocol. But right now, the method from which we derived the
protocol, the formalization of the styles of operational semantics implementations, and
the preliminary results shown in this section demonstrate the worth of this approach,
and we hope that it will serve as a basis for future work on this topic.

6.4 Discussion

In this chapter, we motivated the need for an execution protocol that all operational
semantics should consider in order to support the creation of a generic tool associated
with the execution environment of a language. We defined precisely the boundaries
of such a protocol, and we promoted a formal model to characterize the behavior of
an interpreter supporting it. We highlighted the applicability of the approach to two
different languages and the ability to obtain a REPL that can be integrated in a notebook,
but also the ability to benefit from a rich debugger for these languages. This work also
gives a path to different perspectives. Firstly, as the state of the execution environment is
saved, it is natural to consider this protocol as a vehicle to support undo in an execution
context within a REPL or a notebook. In this context, it is necessary to think about the
efficient implementation of this mechanism. Next, we can also evaluate the addition
of optional extension points within this minimal protocol to enable tool specialization.
In the community of Software Language Engineering, it exists a permanent quest for
designing generic and a highly specializable core for each language services. In this
chapter, the idea is to show that it is possible to obtain completely generic tools as
long as the operational semantics of a language respect a minimal generic protocol. No
doubt that it could be required to specialize some of these tools for a specific domain,
it will then be necessary to evaluate the impact on the proposed protocol. Another
<figure><img src="image_32.png" /><figcaption>Figure 6.6 – Prototype IDE for QL: run-time view (left), source code (center), REPL (right)</figcaption></figure>

research direction relates to the semantics accessed through this protocol. While the set of exposed services is minimal, they might not all be useful for every scenario. Exploring the concept of self adaptable semantics ([42]) could provide substantial performance gains by, e.g., lowering the granularity of steps when debugging is not necessary, while being invisible to the execution tools that would only interact with the protocol. Finally, it would be interesting to revisit MSOS [57] to evaluate the effort required to implement an MSOS operational semantics specification within an interpreter that respects the protocol proposed in this chapter.
<figure><img src="image_33.png" /></figure>
# CONCLUSION & PERSPECTIVES

## 7.1 Conclusion

The adoption of DSLs relies primarily on their integration in the workflows of their target users. With the advent of language workbenches, designing, implementing and maintaining an external DSL has never been as easy as it today. However, the tools provided to the end users end up being highly dependent on a specific environment (i.e., modeling workbench) that provides features similar to the environment they are already used to. At the same time, supporting multiple environments is an arduous process, as illustrated by previous research works mentioning the *IDE portability problem*.

In this thesis, we explored the use of language protocols such as LSP and DAP as a potential solution, and concluded that these approaches were not good fit for the plethora of peculiar features expected from DSLs. As such, we propose the vision of *IDE as Code*, that relies on providing language features as independent services with explicit dependencies between them. For each language service, a sequence of operations can be defined to be executed after the reception of a particular message through a DSL, and the overall communication protocol of the environment can be derived from these specifications. This answers the first challenge mentioned in Section 1.2. Instead of either providing multiple environments for each specific language and require the user to master them all, a fully integrated environment bloated with features they do not use, or a generic environment missing essential specific features, development environments should be customizable to integrate and support only the services required for a specific DSL, both understood and actually used by the target users. In the case of Web IDEs, this vision also enables the deployment of services on multiple machines, and provides the benefits of microservices architectures such as on demand scaling and fast upgrade cycles.

We then applied this ideology to language runtimes. First we defined *REPL Interpreters*, which are essential artifacts to drive new programming paradigms such as literate and exploratory programming, through a generative approach. This relates directly to the
third challenge mentioned in Section 1.2. Then, we researched the most basic interpreter required to support multiple runtime tools such as *Execution Engines* (interpreters supporting the execution of a complete program while providing an interface to connect addons) and *Omniscient Debuggers*. With an interpreter of this sort, exposing a very minimalist protocol, other execution services can be implemented generically, which ensures semantics consistency between all the different execution services. As generic services running on top of this protocol, we considered a generic REPL interpreter, a generic execution engine, and a generic debugger. These generic services should be able to integrate seamlessly in multiple environments as long as they also expose their own protocol. This hierarchy established between language components answers the second challenge mentioned in Section 1.2.

However, the work actually done on the topic of *IDE as Code* is still at an early stage. First of all, while we have proven the advantages of the approach for the subset of runtime components, others have not yet been explored. The advantages of the microservicization of textual editing services has been researched by Coulon et al. in [25], and graphical editing services are also starting to be considered ([7]), but others such as visual representations during animation (like the animation framework presented in [17]) are still to be addressed. The actual integration of all these services in a popular IDE such as *VS Code* would be a valuable contribution to evaluate the overall approach discussed in this manuscript.

In the rest of this chapter, we will list perspectives for future works on this topic which we deem necessary before we can safely envision any adoption.

## 7.2 Perspectives

Our vision, summarized as *IDE as Code*, places the language protocol specification in the adaptation loop of the IDE, where language services are packaged and deployed dynamically, and provided as new capabilities to the user. From our preliminary explored implementations, we identify and discuss concrete challenges in the following section.

**Unified representation of language services specifications** As mentioned in Section 3.2, this work done on this topic focused mainly on the specification and deployment of language packages, and their interactions. We do not target a specific representation of the specifications of languages and their services. In Chapter 6, we consider interactions
made through the use of JSON-RPC protocols, but it is still too early to suggest this
technology for every language service. At the very least, we require a way to specify the
interactions between services completely independent of any specific technology, and a
generative approach to derive the language service packages from these. A first step in
this direction would be a formalization of the generic concepts offered by multiple data
transport technologies, such as JSON-RPC, GraphQL, and REST.

**Domain-specific IDEs concepts** Chapter 6 proposed a first categorization of IDE-specific concepts, such as workspaces and UI services. While we consider these first concepts sound for full-fledged IDEs, it is not yet clear how traditional UI services translate to other development platforms such as Notebooks, or Terminal UIs like (neo)vi(m) or Emacs. Subsequent work is required to properly categorize these concepts and introduce them as first-class constructs to specify language protocols.

**Stateless vs stateful trade-off** Microservice architectures efficiently support resources scaling. But in practice, it is unlikely that every language package will be stateless. For instance, a package to manage the workspace definitely requires a concept of session, and possibly access to a database. To support web-based IDEs in practice, it is necessary to provide a way to specify the stored context of the different packages, and still be able to support scaling even with stateful microservices, probably through synchronization mechanisms that language designers should not have to manage.

**Automation of the deployment** Our vision revolves around an automatic deployment of the “language service packages” and their integration into IDEs, based on properly defined constraints. For “backend” services, this requires either a generative approach, or an interpreter (possibly with an adaptation loop to automate scaling depending on the available resources and the demand) to process the protocol specifications. Further considerations need to be taken into account for UI services, as their deployment would end up being quite specific to the targeted environment.

**Measuring the impact on performances** A direct consequence of microservicizing the different language services will be a multiplication of the number of messages exchanged to complete any action, and numerous asynchronous waits. Beyond flexibility, scaling and collaboration, the hit in performances could be significant at the level of a fully-featured
IDE. A proper study of the possible impacts of this approach to the user experience is required. It is worth investigating alternatives, such as approaches to automatically compile different language service packages (possibly dynamically) back into bigger components when they are deployed on the same machine. Other technical choices for the serialization format (e.g., XML, protobuf) and the transport layer (e.g., pipes, WebRTC) should also be considered and chosen dynamically depending on the proximity with the deployed services.
BIBLIOGRAPHY

[1] Ibrahim S. Abdullah and Daniel A. Menascé, « The Meta-Protocol framework », in: *Journal of Systems and Software* 86.11 (2013), pp. 2711–2724, ISSN: 0164-1212, DOI: https://doi.org/10.1016/j.jss.2013.05.096, URL: http://www.sciencedirect.com/science/article/pii/S0164121213001386 (cit. on p. 37).

[2] Mathieu Acher, Benoit Combemale, and Philippe Collet, « Metamorphic Domain-Specific Languages: A Journey Into the Shapes of a Language », in: *Onward! Essays*, Portland, United States: ACM, Sept. 2014, pp. 243–253, DOI: 10.1145/2661136.2661159, URL: https://hal.inria.fr/hal-01061576 (cit. on p. 75).

[3] Eric Allen, Robert Cartwright, and Brian Stoler, « DrJava: A Lightweight Pedagogic Environment for Java », in: *Proceedings of the 33rd SIGCSE Technical Symposium on Computer Science Education*, SIGCSE’02, Cincinnati, Kentucky: ACM, 2002, pp. 137–141, ISBN: 1-58113-473-8, DOI: 10.1145/563340.563395, URL: http://doi.acm.org/10.1145/563340.563395 (cit. on p. 75).

[4] Marc Andreessen, « Why software is eating the world », in: *Wall Street Journal* 20.2011 (2011), p. C2 (cit. on p. 97).

[5] Andrew W. Appel and Jens Palsberg, *Modern Compiler Implementation in Java*, 2nd, Cambridge University Press, 2003, ISBN: 052182060X (cit. on p. 59).

[6] Bas Basten, Jeroen van den Bos, Mark Hills, Paul Klint, Arnold Lankamp, Bert Lisser, Atze van der Ploeg, Tijs van der Storm, and Jurgen Vinju, « Modular language implementation in Rascal – experience report », in: *Science of Computer Programming* 114 (2015), pp. 7–19, ISSN: 0167-6423, DOI: https://doi.org/10.1016/j.scico.2015.11.003, URL: http://www.sciencedirect.com/science/article/pii/S0167642315003524 (cit. on pp. 54, 56).

[7] Romain Belafia, Pierre Jeanjean, Olivier Barais, Gurvan Le Guernic, and Benoit Combemale, « From Monolithic to Microservice Architecture: The Case of Extensible and Domain-Specific IDEs », in: *MODELS 2021: ACM/IEEE 24th International Conference on Model Driven Engineering Languages and Systems*, Virtual, Japan:
IEEE, Oct. 2021, pp. 1–10, URL: https://hal.inria.fr/hal-03342678 (cit. on pp. 25, 122).

[8] Federico Bergenti, Eleonora Iotti, Stefania Monica, and Agostino Poggi, « Interaction Protocols in the JADEL Programming Language », in: Proceedings of the 6th International Workshop on Programming Based on Actors, Agents, and Decentralized Control, AGERE 2016, Amsterdam, Netherlands: Association for Computing Machinery, 2016, pp. 11–20, ISBN: 9781450346399, DOI: 10.1145/3001886.3001888, URL: https://doi.org/10.1145/3001886.3001888 (cit. on p. 37).

[9] Valentin Besnard, Matthias Brun, Philippe Dhaussy, Frédéric Jouault, David Olivier, and Ciprian Teodorov, « Towards One Model Interpreter for Both Design and Deployment », in: Proceedings of MODELS 2017 Satellite Event: Workshops (ModComp, ME, EXE, COMMitMDE, MRT, MULTI, GEMOC, MoDeVVa, MDETools, FlexMDE, MDE-bug), Posters, Doctoral Symposium, Educator Symposium, ACM Student Research Competition, and Tools and Demonstrations co-located with ACM/IEEE 20th International Conference on Model Driven Engineering Languages and Systems (MODELS 2017), Austin, TX, USA, September, 17, 2017, ed. by Loli Burgueño, Jonathan Corley, Nelly Bencomo, Peter J. Clarke, Philippe Collet, Michalis Famelis, Sudipto Ghosh, Martin Gogolla, Joel Greenyer, Esther Guerra, Sahar Kokaly, Alfonso Pierantonio, Julia Rubin, and Davide Di Ruscio, vol. 2019, CEUR Workshop Proceedings, CEUR-WS.org, 2017, pp. 102–108, URL: http://ceur-ws.org/Vol-2019/exe_4.pdf (cit. on p. 32).

[10] L. Thomas van Binsbergen, eFLINT implementation on GitLab, https://gitlab.com/calculemus-flint/eflint-tools/eflint, [Online, accessed 12 October 2020], 2020 (cit. on p. 68).

[11] L. Thomas van Binsbergen, Lu-Chi Liu, Robert van Doesburg, and Tom van Engers, « eFLINT: A Domain-Specific Language for Executable Norm Specifications », in: Proceedings of the 19th ACM SIGPLAN International Conference on Generative Programming: Concepts and Experiences, GPCE 2020, ACM, 2020, DOI: 10.1145/3425898.3426958 (cit. on p. 68).

[12] L. Thomas van Binsbergen, Peter D. Mosses, and Neil Sculthorpe, « Executable Component-Based Semantics », in: Journal of Logical and Algebraic Methods in Programming 103 (Feb. 2019), pp. 184–212, DOI: 10.1016/j.jlamp.2018.12.004 (cit. on p. 110).
[13] L. Thomas van Binsbergen, Elizabeth Scott, and Adrian Johnstone, « Purely func-
tional GLL parsing », in: *Journal of Computer Languages* 58 (2020), p. 100945,
DOI: 10.1016/j.cola.2020.100945 (cit. on p. 109).

[14] L. Thomas van Binsbergen and Neil Sculthorpe, *The Haskell Funcon Framework*, Hackage, [Online, accessed on the 13th of April 2022], 2018, URL: https://hackage.haskell.org/package/funcons-tools (cit. on p. 110).

[15] L. Thomas van Binsbergen, Mauricio Verano Merino, Pierre Jeanjean, Tijs van der Storm, Benoit Combemale, and Olivier Barais, « A Principled Approach to REPL Interpreters », in: *Proceedings of the 2020 ACM SIGPLAN International Symposium on New Ideas, New Paradigms, and Reflections on Programming and Software*, Onward! 2020, Virtual, USA: Association for Computing Machinery, 2020, pp. 84–100, ISBN: 9781450381789, DOI: 10.1145/3426428.3426917, URL: https://doi.org/10.1145/3426428.3426917 (cit. on pp. 25, 30, 47, 52, 99, 101, 104, 105, 106, 107).

[16] Meinte Boersma, *Are language workbenches dead?*, 2017, URL: https://medium.com/@dslmeinte/are-language-workbenches-dead-4b05d1698d3c (cit. on p. 34).

[17] Erwan Bousse, Thomas Degueule, Didier Vojtisek, Tanja Mayerhofer, Julien Deantoni, and Benoit Combemale, « Execution Framework of the GEMOC Studio (Tool Demo) », in: *Proceedings of the 2016 ACM SIGPLAN International Conference on Software Language Engineering*, SLE 2016, Amsterdam, Netherlands: Association for Computing Machinery, 2016, pp. 84–89, ISBN: 9781450344470, DOI: 10.1145/2997364.2997384, URL: https://doi.org/10.1145/2997364.2997384 (cit. on pp. 18, 33, 81, 99, 100, 122).

[18] Erwan Bousse, Dorian Leroy, Benoit Combemale, Manuel Wimmer, and Benoit Baudry, « Omniscient Debugging for Executable DSLs », in: *Journal of Systems and Software* 137 (Mar. 2018), pp. 261–288, DOI: 10.1016/j.jss.2017.11.025, URL: https://hal.inria.fr/hal-01662336 (cit. on pp. 15, 16, 23, 42, 100, 107).

[19] Mark van den Brand, B. Cornelissen, Pieter A. Olivier, and Jurgen J. Vinju, « TIDE: A Generic Debugging Framework - Tool Demonstration », in: *Electron. Notes Theor. Comput. Sci.* 141.4 (2005), pp. 161–165, DOI: 10.1016/j.entcs.2005.02.056, URL: https://doi.org/10.1016/j.entcs.2005.02.056 (cit. on p. 34).
[20] Mark van den Brand, Arie van Deursen, Jan Heering, Hayco de Jong, Merijn de Jonge, Tobias Kuipers, Paul Klint, Leon Moonen, Pieter A. Olivier, Jeroen Scheerder, Jurgen J. Vinju, Eelco Visser, and Joost Visser, « The Asf+Sdf Meta-Environment: a Component-Based Language Development Environment », in: *Electron. Notes Theor. Comput. Sci.* 44.2 (2001), pp. 3–8, DOI: 10.1016/S1571-0661(04)80917-4, URL: https://doi.org/10.1016/S1571-0661(04)80917-4 (cit. on p. 34).

[21] Hendrik Bünder, « Decoupling Language and Editor - The Impact of the Language Server Protocol on Textual Domain-Specific Languages », in: *Proceedings of the 7th International Conference on Model-Driven Engineering and Software Development - Volume 1: MODELSWARD*, INSTICC, SciTePress, 2019, pp. 131–142, ISBN: 978-989-758-358-2, DOI: 10.5220/0007556301310142 (cit. on pp. 9, 17, 18, 34).

[22] L. Burgy, L. Reveillere, J. Lawall, and G. Muller, « Zebu: A Language-Based Approach for Network Protocol Message Processing », in: *IEEE Transactions on Software Engineering* 37.4 (2011), pp. 575–591 (cit. on p. 37).

[23] João Cangussu, Jens Palsberg, and Vidyut Samanta, *The MiniJava Project*, https://www.cambridge.org/us/features/052182060X, [Online, accessed 12 October 2020], 2002 (cit. on p. 59).

[24] Andrei Chis, Tudor Gîrba, and Oscar Nierstrasz, « The Moldable Debugger: A Framework for Developing Domain-Specific Debuggers », in: *Software Language Engineering - 7th International Conference, SLE 2014, Västerås, Sweden, September 15-16, 2014. Proceedings*, ed. by Benoît Combemale, David J. Pearce, Olivier Barais, and Jurgen J. Vinju, vol. 8706, Lecture Notes in Computer Science, Springer, 2014, pp. 102–121, DOI: 10.1007/978-3-319-11245-9FFF_6, URL: https://doi.org/10.1007/978-3-319-11245-9_6 (cit. on p. 35).

[25] Fabien Coulon, Alex Auvolat, Benoît Combemale, Yérom-David Bromberg, François Taïani, Olivier Barais, and Noël Plouzeau, « Modular and Distributed IDE », in: *SLE 2020 - 13th ACM SIGPLAN International Conference on Software Language Engineering*, Virtual, United States, Nov. 2020, DOI: 10.1145/3426425.3426947, URL: https://hal.archives-ouvertes.fr/hal-02964806 (cit. on pp. 13, 21, 42, 122).

[26] Fabien Coulon, Thomas Degueule, Tijs Van Der Storm, and Benoît Combemale, « Shape-Diverse DSLs: Languages without Borders (Vision Paper) », in: *SLE 2018 - 11th ACM SGIPLAN International Conference on Software Language Engineering*,
Boston, United States: ACM, Nov. 2018, pp. 215–219, DOI: 10.1145/3276604.3276623, URL: https://hal.archives-ouvertes.fr/hal-01889155 (cit. on p. 94).

[27] Peter Deutsch, *PDP-1 LISP*, tech. rep., http://www.bitsavers.org/pdf/mit/rle_pdp1/memos/Deutsch_PDP-1_LISP.pdf, MIT Research Laboratory for Electronics, 1964 (cit. on p. 35).

[28] Sebastian Erdweg, Tijs van der Storm, Markus Volter, Laurence Tratt, Remi Bosman, William R. Cook, Albert Gerritsen, Angelo Hulshout, Steven Kelly, Alex Loh, Gabriel Konat, Pedro J. Molina, Martin Palatnik, Risto Pohjonen, Eugen Schindler, Klemens Schindler, Riccardo Solmi, Vlad Vergu, Eelco Visser, Kevin van der Vlist, Guido Wachsmuth, and Jimi van der Woning, « Evaluating and comparing language workbenches: Existing results and benchmarks for the future », in: *Computer Languages, Systems & Structures* 44 (2015), pp. 24–47, ISSN: 1477-8424, DOI: 10.1016/j.cl.2015.08.007 (cit. on pp. 30, 55, 64).

[29] Sebastian Erdweg, Tijs van der Storm, Markus Völter, Meinte Boersma, Remi Bosman, William R. Cook, Albert Gerritsen, Angelo Hulshout, Steven Kelly, Alex Loh, Gabriël D. P. Konat, Pedro J. Molina, Martin Palatnik, Risto Pohjonen, Eugen Schindler, Klemens Schindler, Riccardo Solmi, Vlad A. Vergu, Eelco Visser, Kevin van der Vlist, Guido Wachsmuth, and Jimi van der Woning, « The State of the Art in Language Workbenches - Conclusions from the Language Workbench Challenge », in: *Proceedings of the 6th International Conference on Software Language Engineering (SLE’13)*, 2013, pp. 197–217, DOI: 10.1007/978-3-319-02654-1_11, URL: https://doi.org/10.1007/978-3-319-02654-1_11 (cit. on p. 64).

[30] Moritz Eysholdt and Heiko Behrens, « Xtext: implement your language faster than the quick and dirty way », in: *Proceedings of the ACM international conference companion on Object oriented programming systems languages and applications companion*, 2010, pp. 307–309 (cit. on p. 98).

[31] Robert Bruce Findler, Cormac Flanagan, Matthew Flatt, Shriram Krishnamurthi, and Matthias Felleisen, « DrScheme: A pedagogic programming environment for scheme », in: *Programming Languages: Implementations, Logics, and Programs*, ed. by Hugh Glaser, Pieter Hartel, and Herbert Kuchen, Berlin, Heidelberg: Springer Berlin Heidelberg, 1997, pp. 369–388, ISBN: 978-3-540-69537-0, DOI: 10.1007/BFb0033856 (cit. on p. 75).
[32] Martin Fowler, *Language Workbenches: The Killer-App for Domain Specific Languages?*, 2005, URL: http://martinfowler.com/articles/languageWorkbench.html (cit. on p. 33).

[33] Maria Gouseti, Chiel Peters, and Tijs van der Storm, « Extensible Language Implementation with Object Algebras (Short Paper) », in: *Proceedings of the 2014 International Conference on Generative Programming: Concepts and Experiences (GPCE’14)*, Västerås, Sweden, 2014, pp. 25–28, DOI: 10.1145/2658761.2658765, URL: https://doi.org/10.1145/2658761.2658765 (cit. on p. 54).

[34] Kathryn E. Gray and Matthew Flatt, « ProfessorJ: A Gradual Introduction to Java Through Language Levels », in: *Companion of the 18th Annual ACM SIGPLAN Conference on Object-oriented Programming, Systems, Languages, and Applications*, OOPSLA’03, Anaheim, CA, USA: ACM, 2003, pp. 170–177, ISBN: 1-58113-751-6, DOI: 10.1145/949344.949394, URL: http://doi.acm.org/10.1145/949344.949394 (cit. on p. 75).

[35] Object Management Group, *Semantics of a Foundational Subset for Executable UML Models, v1.5*, 2021, URL: https://www.omg.org/spec/FUML/1.5/About-FUML/ (cit. on p. 32).

[36] Sahar Guermazi, Jérémie Tatibouet, Arnaud Cuccuru, Ed Seidewitz, Saadia Dhouib, and Sébastien Gérard, « Executable Modeling with fUML and Alf in Papyrus: Tooling and Experiments », in: *EXE@MODELS*, 2015 (cit. on p. 33).

[37] Juhana Harmanen and Tommi Mikkonen, « On Polyglot Programming in the Web », in: *Modern Software Engineering Methodologies for Mobile and Cloud Environments*, IGI Global, 2016, pp. 102–119, DOI: 10.4018/978-1-4666-9916-8.ch006, URL: https://doi.org/10.4018/978-1-4666-9916-8.ch006 (cit. on pp. 9, 17, 28).

[38] Anastasia Izmaylova, Ali Afroozeh, and Tijs Van Der Storm, « Practical, General Parser Combinators », in: *Proceedings of the 2016 ACM SIGPLAN Workshop on Partial Evaluation and Program Manipulation*, PEPM 2016, ACM, 2016, pp. 1–12, ISBN: 978-1-4503-4097-7, DOI: 10.1145/2847538.2847539, URL: http://doi.acm.org/10.1145/2847538.2847539 (cit. on p. 109).

[39] Pierre Jeanjean, Benoit Combemale, and Olivier Barais, « From DSL Specification to Interactive Computer Programming Environment », in: *Proceedings of the 12th ACM SIGPLAN International Conference on Software Language Engineering*, SLE
2019, Athens, Greece: Association for Computing Machinery, 2019, pp. 167–178, ISBN: 9781450369817, DOI: 10.1145/3357766.3359540, URL: https://doi.org/10.1145/3357766.3359540 (cit. on pp. 25, 75, 99, 111).

[40] Pierre Jeanjean, Benoit Combemale, and Olivier Barais, « IDE as Code: Reifying Language Protocols as First-Class Citizens », in: *14th Innovations in Software Engineering Conference (Formerly Known as India Software Engineering Conference)*, New York, NY, USA: Association for Computing Machinery, 2021, ISBN: 9781450390460, URL: https://doi.org/10.1145/3452383.3452406 (cit. on pp. 25, 39).

[41] Mark Johnson, « Memoization in Top-down Parsing », in: *Computational Linguistics* 21.3 (1995), pp. 405–417, ISSN: 0891-2017 (cit. on p. 109).

[42] Gwendal Jouneaux, Olivier Barais, Benoit Combemale, and Gunter Mussbacher, « Towards Self-Adaptable Languages », in: *Proceedings of the 2021 ACM SIGPLAN International Symposium on New Ideas, New Paradigms, and Reflections on Programming and Software*, Onward! 2021, Chicago, IL, USA: Association for Computing Machinery, 2021, pp. 97–113, ISBN: 9781450391108, DOI: 10.1145/3486607.3486753, URL: https://doi.org/10.1145/3486607.3486753 (cit. on p. 119).

[43] Kyo C. Kang, Sholom G. Cohen, James A. Hess, William E. Novak, and A. Spencer Peterson, *Feature-oriented domain analysis (FODA) feasibility study*, tech. rep., Carnegie-Mellon Software Engineering Institute, 1990 (cit. on p. 49).

[44] Sven Keidel, Wulf Pfeiffer, and Sebastian Erdweg, « The IDE portability problem and its solution in Monto », in: *Proceedings of the 2016 ACM SIGPLAN International Conference on Software Language Engineering, Amsterdam, The Netherlands, October 31 - November 1, 2016*, ed. by Tijs van der Storm, Emilie Balland, and Dániel Varró, ACM, 2016, pp. 152–162, URL: http://dl.acm.org/citation.cfm?id=2997368 (cit. on p. 34).

[45] Mary Beth Kery and Brad A Myers, « Exploring exploratory programming », in: *2017 IEEE Symposium on Visual Languages and Human-Centric Computing (VL/HCC)*, IEEE, 2017, pp. 25–29 (cit. on pp. 15, 23).

[46] Paul Klint, A. Taeke Kooiker, and Jurgen J. Vinju, « Language Parametric Module Management for IDEs », in: *Electron. Notes Theor. Comput. Sci.* 203.2 (2008), pp. 3–19, DOI: 10.1016/j.entcs.2008.03.041, URL: https://doi.org/10.1016/j.entcs.2008.03.041 (cit. on p. 34).
[47] Paul Klint, Tijs van der Storm, and Jurgen Vinju, « Rascal: A Domain Specific Language for Source Code Analysis and Manipulation », in: *Proceedings of the 2009 Ninth IEEE International Working Conference on Source Code Analysis and Manipulation*, IEEE Computer Society, 2009, pp. 168–177, ISBN: 978-0-7695-3793-1, DOI: 10.1109/SCAM.2009.28 (cit. on pp. 56, 59, 98).

[48] Thomas Kluyver, Benjamin Ragan-Kelley, Fernando Pérez, Brian Granger, Matthias Bussonnier, Jonathan Frederic, Kyle Kelley, Jessica Hamrick, Jason Grout, Sylvain Corlay, Paul Ivanov, Damián Avila, Safia Abdalla, and Carol Willing, « Jupyter Notebooks – a publishing format for reproducible computational workflows », in: *Positioning and Power in Academic Publishing: Players, Agents and Agendas*, 2016, pp. 87–90, DOI: 10.3233/978-1-61499-649-1-87 (cit. on pp. 30, 36, 98).

[49] Donald Ervin Knuth, « Literate programming », in: *The computer journal* 27.2 (1984), pp. 97–111 (cit. on pp. 15, 23).

[50] Jan Koehnlein, « Beyond LSP: Getting Your Language into Theia and VS Code », EclipseCon 2020, 2020, URL: https://www.eclipsecon.org/2020/sessions/beyond-lsp-getting-your-language-theia-and-vs-code (cit. on pp. 10, 19).

[51] Yoann Laurent, Reda Bendraou, and Marie-Pierre Gervais, « Executing and Debugging UML Models: An FUML Extension », in: *Proceedings of the 28th Annual ACM Symposium on Applied Computing*, SAC ’13, Coimbra, Portugal: Association for Computing Machinery, 2013, pp. 1095–1102, ISBN: 9781450316569, DOI: 10.1145/2480362.2480569, URL: https://doi.org/10.1145/2480362.2480569 (cit. on p. 33).

[52] Dorian Leroy, Pierre Jeanjean, Erwan Bousse, Manuel Wimmer, and Benoit Combe-male, « Runtime Monitoring for Executable DSLs », in: *J. Object Technol.* 19.2 (2020), 6:1–23, DOI: 10.5381/jot.2020.19.2.a6, URL: https://doi.org/10.5381/jot.2020.19.2.a6 (cit. on pp. 26, 100).

[53] Bil Lewis, « Debugging Backwards in Time », in: *Computing Research Repository* cs.SE/0310016 (2003), URL: http://arxiv.org/abs/cs/0310016 (cit. on p. 107).

[54] J. McCarthy, R. Brayton, D. Edwards, P. Fox, L. Hodes, D. Luckham, K. Maling, and D. Park S. Russell, *Lisp I programmer's manual*, http://history.siam.org/sup/Fox_1960_LISP.pdf. [Online, accessed 12 October 2020], Computation Center and Research Laboratory of Electronics (MIT), 1960 (cit. on p. 35).
[55] Mauricio Verano Merino, Jurgen J. Vinju, and Tijs van der Storm, « Bacatá: Notebooks for DSLs, Almost for Free », in: *Programming Journal* 4.3 (2020), p. 11, DOI: 10.22152/programming-journal.org/2020/4/11, URL: https://doi.org/10.22152/programming-journal.org/2020/4/11 (cit. on pp. 36, 62).

[56] Marjan Mernik, Jan Heering, and Anthony M. Sloane, « When and How to Develop Domain-specific Languages », in: *ACM Computing Surveys* 37.4 (2005), pp. 316–344, ISSN: 0360-0300, DOI: 10.1145/1118890.1118892 (cit. on p. 55).

[57] Peter D. Mosses, « Modular Structural Operational Semantics », in: *Journal of Logic and Algebraic Programming* 60–61 (2004), pp. 195–228, DOI: 10.1016/j.jlap.2004.03.008 (cit. on p. 119).

[58] Gunter Mussbacher, Benoit Combemale, Jörg Kienzle, Silvia Abrahão, Hyacinth Ali, Nelly Bencomo, Márton Búr, Loli Burgueño, Gregor Engels, Pierre Jeanjean, Jean-Marc Jézéquel, Thomas Kühn, Sébastien Mosser, Houari Sahraoui, Eugene Syriani, Dániel Varró, and Martin Weyssow, « Opportunities in intelligent modeling assistance », in: *Software and Systems Modeling* 19.5 (Sept. 2020), pp. 1045–1053, ISSN: 1619-1374, DOI: 10.1007/s10270-020-00814-5, URL: https://doi.org/10.1007/s10270-020-00814-5 (cit. on p. 26).

[59] P. S. Newman, « Towards an Integrated Development Environment », in: *IBM Syst. J.* 21.1 (Mar. 1982), pp. 81–107, ISSN: 0018-8670, DOI: 10.1147/sj.211.0081, URL: https://doi.org/10.1147/sj.211.0081 (cit. on p. 27).

[60] Fabio Niephaus, Patrick Rein, Jakob Edding, Jonas Hering, Bastian König, Kolya Opahle, Nico Scordialo, and Robert Hirschfeld, « Example-Based Live Programming for Everyone: Building Language-Agnostic Tools for Live Programming with LSP and GraalVM », in: *Proceedings of the 2020 ACM SIGPLAN International Symposium on New Ideas, New Paradigms, and Reflections on Programming and Software*, Onward! 2020, Virtual, USA: Association for Computing Machinery, 2020, pp. 1–17, ISBN: 9781450381789, DOI: 10.1145/3426428.3426919, URL: https://doi.org/10.1145/3426428.3426919 (cit. on pp. 10, 19).

[61] Bruno C. d. S. Oliveira and William R. Cook, « Extensibility for the Masses - Practical Extensibility with Object Algebras », in: *ECOOP 2012 – Object-Oriented Programming*, Springer Berlin Heidelberg, 2012, pp. 2–27 (cit. on p. 54).
[62] Fernando Perez and Brian E. Granger, «IPython: A System for Interactive Scientific Computing», in: *Computing in Science and Engineering* 9.3 (2007), pp. 21–29, DOI: 10.1109/MCSE.2007.53 (cit. on p. 36).

[63] F. Plasil and S. Visnovsky, «Behavior protocols for software components», in: *IEEE Transactions on Software Engineering* 28.11 (2002), pp. 1056–1076 (cit. on p. 36).

[64] Gordon D. Plotkin, «A Structural Approach to Operational Semantics», in: *Journal of Logic and Algebraic Programming* 60–61 (2004), Reprint of Technical Report FN-19, DAIMI, Aarhus University, 1981, pp. 17–139, DOI: 10.1016/j.jlap.2004.05.001 (cit. on pp. 104, 109).

[65] Jonas Kjær Rask, Frederik Palludan Madsen, Nick Battle, Hugo Daniel Macedo, and Peter Gorm Larsen, «The Specification Language Server Protocol: A Proposal for Standardised LSP Extensions», in: *CoRR abs/2108.02961* (2021), arXiv: 2108.02961, URL: https://arxiv.org/abs/2108.02961 (cit. on pp. 9, 17).

[66] Elizabeth D. Rather, Donald R. Colburn, and Charles H. Moore, «The Evolution of Forth», in: *The Second ACM SIGPLAN Conference on History of Programming Languages*, HOPL-II, Cambridge, Massachusetts, USA: ACM, 1993, pp. 177–199, ISBN: 0897915704, DOI: 10.1145/154766.155369, URL: https://doi.org/10.1145/154766.155369 (cit. on p. 35).

[67] Eric Roberts, «An Overview of MiniJava», in: *Proceedings of the Thirty-Second SIGCSE Technical Symposium on Computer Science Education*, SIGCSE '01, Charlotte, North Carolina, USA: Association for Computing Machinery, 2001, pp. 1–5, ISBN: 1581133294, DOI: 10.1145/364447.364525, URL: https://doi.org/10.1145/364447.364525 (cit. on pp. 90, 99).

[68] Roberto Rodriguez-Echeverria, Javier Luis Cánovas Izquierdo, Manuel Wimmer, and Jordi Cabot, «Towards a Language Server Protocol Infrastructure for Graphical Modeling», in: *Proceedings of the 21st ACM/IEEE International Conference on Model Driven Engineering Languages and Systems*, MODELS '18, Copenhagen, Denmark: Association for Computing Machinery, 2018, pp. 370–380, ISBN: 9781450349499, DOI: 10.1145/3239372.3239383, URL: https://doi.org/10.1145/3239372.3239383 (cit. on pp. 9, 10, 17, 18).
[69] Tobias Roehm, Rebecca Tiarks, Rainer Koschke, and Walid Maalej, « How Do Professional Developers Comprehend Software? », in: *Proceedings of the 34th International Conference on Software Engineering*, ICSE '12, Zurich, Switzerland: IEEE Press, 2012, pp. 255–265, ISBN: 9781467310673 (cit. on pp. 13, 21, 28).

[70] Riemer van Rozen and Tijs van der Storm, « Toward live domain-specific languages – From text differencing to adapting models at run time », in: *Softw. Syst. Model*. 18.1 (2019), pp. 195–212, DOI: 10.1007/s10270-017-0608-7, URL: https://doi.org/10.1007/s10270-017-0608-7 (cit. on p. 117).

[71] Adam Rule, Aurélien Tabard, and James D. Hollan, « Exploration and Explanation in Computational Notebooks », in: *Proceedings of the 2018 CHI Conference on Human Factors in Computing Systems*, New York, NY, USA: Association for Computing Machinery, 2018, pp. 1–12, ISBN: 9781450356206, URL: https://doi.org/10.1145/3173574.3173606 (cit. on p. 30).

[72] J. C. Shaw, « JOSS: A designer's view of an experimental on-line computing system », in: *AFZPS Conference Proceedings, vol. 26, 1964 Fall Joint Computer Conference*, 1964, pp. 455–464 (cit. on pp. 35, 36).

[73] Janet Siegmund, « Program Comprehension: Past, Present, and Future », in: *2016 IEEE 23rd International Conference on Software Analysis, Evolution, and Reengineering (SANER)*, vol. 5, 2016, pp. 13–20, DOI: 10.1109/SANER.2016.35 (cit. on p. 28).

[74] Dave Steinberg, Frank Budinsky, Ed Merks, and Marcelo Paternostro, *EMF: eclipse modeling framework*, Pearson Education, 2008 (cit. on p. 81).

[75] Tijs van der Storm, « Semantic Deltas for Live DSL Environments», in: *Proceedings of the 1st International Workshop on Live Programming*, LIVE '13, IEEE, San Francisco, California: IEEE Press, 2013, pp. 35–38, ISBN: 9781467362658, DOI: 10.1109/LIVE.2013.6617347 (cit. on pp. 72, 117).

[76] Walid Taha, « A Gentle Introduction to Multi-stage Programming », in: *Domain-Specific Program Generation: International Seminar, Dagstuhl Castle, Germany, March 23-28, 2003. Revised Papers*, ed. by Christian Lengauer, Don Batory, Charles Consel, and Martin Odersky, Berlin, Heidelberg: Springer Berlin Heidelberg, 2004, pp. 30–50, ISBN: 978-3-540-25935-0, DOI: 10.1007/978-3-540-25935-0_3, URL: https://doi.org/10.1007/978-3-540-25935-0_3 (cit. on p. 29).
[77] Steven L. Tanimoto, « A perspective on the evolution of live programming », in: *1st International Workshop on Live Programming (LIVE'13)*, IEEE, 2013, pp. 31–34, DOI: 10.1109/LIVE.2013.6617346 (cit. on p. 72).

[78] Warren Teitelman, « History of Interlisp », in: *Celebrating the 50th Anniversary of Lisp*, Nashville, Tennessee: ACM, 2008, ISBN: 9781605583839, DOI: 10.1145/1529966.1529971, URL: https://doi.org/10.1145/1529966.1529971 (cit. on p. 35).

[79] Warren Teitelman, « PILOT: A Step Toward Man-Computer Symbiosis », PhD thesis, MIT, 1966, URL: http://hdl.handle.net/1721.1/6905 (cit. on p. 35).

[80] Federico Tomassetti and Marco Torchiano, « An Empirical Assessment of Polyglot-Ism in GitHub », in: *Proceedings of the 18th International Conference on Evaluation and Assessment in Software Engineering*, EASE '14, London, England, United Kingdom: Association for Computing Machinery, 2014, ISBN: 9781450324762, DOI: 10.1145/2601248.2601269, URL: https://doi.org/10.1145/2601248.2601269 (cit. on pp. 9, 17).

[81] April Yi Wang, Anant Mittal, Christopher Brooks, and Steve Oney, « How Data Scientists Use Computational Notebooks for Real-Time Collaboration », in: *Proc. ACM Hum.-Comput. Interact.* 3.CSCW (Nov. 2019), DOI: 10.1145/3359141, URL: https://doi.org/10.1145/3359141 (cit. on p. 30).

[82] Stephen Wolfram, *The Mathematica Book (4th Edition)*, USA: Cambridge University Press, 1999, ISBN: 0521643147 (cit. on p. 36).

[83] Ziv Yaniv, Bradley C Lowekamp, Hans J Johnson, and Richard Beare, « Correction to: SimpleITK Image-Analysis Notebooks: a Collaborative Environment for Education and Reproducible Research », en, in: *J Digit Imaging* 32.6 (Dec. 2019), p. 1118 (cit. on p. 30).

[84] Steffen Zschaler, « Adding a HenshinEngine to GEMOC Studio: An experience report », in: *Proceedings of MODELS 2018 Workshops: ModComp, MRT, OCL, FlexMDE, EXE, COMMitMDE, MDETools, GEMOC, MORSE, MDE4IoT, MDEbug, MoDeVVa, ME, MULTI, HuFaMo, AMMoRe, PAINS co-located with ACM/IEEE 21st International Conference on Model Driven Engineering Languages and Systems (MODELS 2018)*, Copenhagen, Denmark, October, 14, 2018, ed. by Regina Hebig and Thorsten Berger, vol. 2245, CEUR Workshop Proceedings, CEUR-WS.org, 2018, pp. 429–431, URL: http://ceur-ws.org/Vol-2245/gemoc_paper_5.pdf (cit. on p. 100).
<figure><img src="image_34.png" /></figure>
<figure><img src="image_35.png" /></figure>

**Titre** : Environnements de Développement Programmables : Réification des Protocoles de Langage en Objets de Première Classe

**Mot clés** : Génie logiciel, Générateurs (logiciels), Langages dédiés, Interpréteurs (logiciels)

**Résumé** : L'utilisation de langages de programmation modernes et complexes nécessite des environnements de développement dédiés, capables d'assister les programmeurs. Les environnements de développement intégrés (IDE) sont les environnements les plus utilisés aujourd'hui, fournissant tous les outils nécessaires pour utiliser efficacement les langages qu'ils ciblent. Fournir un IDE complet pour un langage spécifique est cependant très coûteux, ce qui conduit leurs mainteneurs à ne se concentrer que sur quelques langages pour chaque IDE, divisant ainsi leurs utilisateurs. Afin de rester pertinents, les petits langages tels que les langages dédiés (DSL) doivent être correctement intégrés dans l'environnement de leurs utilisateurs, ce qui nécessite de vastes ressources et ne peut pas prendre en compte la fragmentation entre les IDEs. Dans cette thèse, nous explorons l'idée de déployer des environnements de développement

adaptés aux besoins de leurs utilisateurs, et de tirer parti d'outils de langages complètement séparés de tout IDE spécifique. Nous commençons par considérer les protocoles de langage, tels que LSP, et concevons une alternative modulaire et extensible qui correspond mieux aux spécificités des DSLs. Ensuite, nous nous concentrons sur les interpréteurs REPL, des interpréteurs de langage interactifs qui ont une grande valeur pour l'éducation et l'exploration, mais qui ne sont pas facilement dérivés à partir des techniques d'ingénierie des langages existantes. Nous proposons une approche formelle pour définir les REPLs, ainsi qu'une approche générative, et discutons de leur intégration dans les environnements de développement. Enfin, nous unifions la sémantique de plusieurs outils d'exécution (moteurs d'exécution, REPLs et débugueurs) par la spécification du protocole minimal entre eux.

**Title:** IDE as Code: Reifying Language Protocols as First-Class Citizens

**Keywords:** Software engineering, Generators (Computer programs), Domain-specific programming languages, Interpreters (Computer programs)

**Abstract:** The use of modern and complex programming languages requires dedicated development environments to support programmers. Integrated Development Environments (IDEs) are the most used environments today, providing all the necessary tools to use efficiently the languages they target. Providing a complete IDE for a specific language is however very costly, which lead to their

maintainers to only focus on a few languages for each IDE, splitting their users. In order to stay relevant, small languages such as domain-specific languages (DSLs) need to be properly integrated in the environment of their users, which requires vast resources and cannot scale to the fragmentation of IDEs. In this thesis, we explore the idea of deploying development environments customized to the
needs of their users, and leveraging language tools completely separated from any specific IDE. We start by considering language protocols, such as LSP, and designing a modular and extensible alternative that is more in line with the specificities of DSLs. Then, we focus on REPL interpreters, interactive language interpreters which offer great value for education and exploration but are not easily derived from

existing language engineering techniques. We provide a formal approach to define REPLs, as well as a generative approach, and discuss their integration in development environments. Finally, we unify the semantics of several execution tools (execution engines, REPLs and debuggers) through the specification of the minimal protocol between them.