blob: dfd63f6d5fc01d0dbe14a56d88f9be926fd09f1a [file] [log] [blame]
\chapter{Implementing a New Task-Specific Language}
Although Epsilon already provides languages for a wide range of model management tasks, additional tasks that could benefit from the convenience syntax and dedicated semantics of a task-specific language are likely to be identified in the future. Thus, this section distils the experiences obtained through the construction of existing task-specific languages to provide guidance on how to identify a task for which a dedicated language can be beneficial and develop the respective task-specific language for it atop the infrastructure provided by Epsilon.
\section{Identifying the need for a new language}
The first step of the process of constructing a new task-specific language is to identify a specific task for which a dedicated language is more appropriate than the general-purpose EOL. Typically, recurring syntactic and semantic patterns that emerge when attempting to implement the task using EOL indicate that a new task-specific language may be useful.
For example, before the introduction of the Epsilon Comparison Language, pure EOL was being used to perform model comparison. A simple comparison specification that establishes name-based matches between classes/attributes and tables/columns between two OO and DB models respectively using EOL is demonstrated in Listing \ref{lst:ComparisonEOL}.
Two patterns can be readily detected by inspecting the EOL code in Listing \ref{lst:ComparisonEOL}. First, explicit variables (\emph{matchingCT}, \emph{matchingAT}) are defined to capture the matching elements (class-table and attribute-column)identified during the comparison process. Also, to check all elements of one type (classes against tables and attributes against columns) repeated for statements are used in lines \ref{line:For11}--\ref{line:For12} and \ref{line:For21}--\ref{line:For22}. By contrast, Listing \ref{lst:ComparisonECL} which is specified using the task-specific ECL language does not include such low-level information. Instead it defines only the types of elements that need to be compared and the criteria on which comparison must performed and leaves the mundane tasks of scheduling and maintaining the match trace to the execution engine.
\begin{lstlisting}[caption=Comparing an OO model with a DB model using EOL, label=lst:ComparisonEOL, language=EOL]
var matchingCT : Sequence; /*@\label{line:MatchTrace1}@*/
var matchingAC : Sequence; /*@\label{line:MatchTrace2}@*/
for (c in OO!Class.allInstances) { /*@\label{line:For11}@*/
for (t in DB!Table.allInstances) { /*@\label{line:For12}@*/
if ( = {
for (att in c.attributes) { /*@\label{line:For21}@*/
for (col in t.columns) { /*@\label{line:For22}@*/
if ( = {
matchingAC.add(Sequence{att, col});
\begin{lstlisting}[caption=Comparing an OO model with a DB model using ECL, label=lst:ComparisonECL, language=ECL]
rule ClassTable
match c : OO!Class
with t : DB!Table {
compare : =
rule AttributeColumn
match a : OO!Attribute
with c : DB!Column {
compare : = and
\section{Eliciting higher-level constructs from recurring patterns}
Once recurring patterns, such as those discussed above, have been identified, the next step of the process is to derive higher level constructs from them. For instance, in the previous example, the nested for loops and the explicit trace variable declaration and population have been replaced by task-specific match rules.
Introducing higher-level involves defining its abstract and concrete syntax as well as its connection points with the underlying infrastructure. For example, in the case of ECL, the types of match rules are EOL model element types, the \emph{guard} and \emph{check} parts of a rule are EOL expressions or statements blocks and the \emph{pre} and \emph{post} blocks as well as the \emph{do} part of each rule are blocks of EOL statements.
\section{Implement Execution Semantics and Scheduling}
Once higher-level constructs (e.g. task-specific rules) have been identified and specified, their execution semantics and scheduling must be implemented similarly to what has been done for existing languages. Development of existing languages has demonstrated that task-specific constructs often need to provide more than one modes of execution (e.g. the \emph{lazy} and \emph{greedy} modes of ETL transformation rules discussed in Section \ref{sec:ETL.ExecutionSemantics}).
A lightweight way to easily provide new execution modes and semantics for rules and user-defined operations without modifying the syntax of the language and introducing new keywords that may conflict with existing code, is through the annotations mechanism provided by EOL (see Section \ref{sec:Design.EOL.Annotations}). This approach has been adopted for the definition a small unit-testing language (EUnit), which is discussed in detail in \cite{EUnit}.
\section{Overriding Semantics}
In certain cases, it is useful to modify the semantics of certain constructs in EOL to meet the purposes of the task-specific language. An example of such a modification occurs in EVL where -- as discussed in Section \ref{sec:Design.EVL.ExecutionSemantics} -- the scope of the variables defined in \emph{guard} expression/block is extended so that variables can be reused in the context of non-nested blocks such as the \emph{title}, and \emph{check} parts of the invariant. Another example of overriding the semantics of EOL is the implementation of the special assignment operator ($::=$) by ETL which was discussed in \ref{sec:Design.ETL.SpecialAssignmentOperator}.