This page presents Metagene translation rules. Some implementation details are not detailed, but the core of the Metagene translator is here presented. This translator is made of two parts: the core program (written in OCaml with the help of Camlp4) and a set of C++ headers which declares all utility classes used by Metagene generated code. Three main kind of constructs are detailed here: Expressions, Patterns (used in pattern matching and function declarations) and Types.
Expressions
Due to complexity of the C++ grammar related to class templates manipulation, nested expression are first splitted into a set of simple expressions. This fist step can be seen as syntaxic sugar.
For example, let f = compose (plus 1) (times 10) is transformed into
let rec temp1 = plus 1
and temp2 = times 10
and temp3 = compose temp1 temp2
and f = temp3 |
So, Metagene only processes expressions of type: let
name = a_simple_expression.
Type constructors
- Integer: (let name = ) intvalue
typedef mtg :: Int < intvalue > name;
// with mtg :: Int defined as
template<int N>
struct Int {
enum {value = N};
}; |
- Char: (let name = ) charvalue
typedef mtg :: Char < charvalue > name;
//with mtg :: Char defined as
template<char C>
struct Char {
static const char value = C;
}; |
[translation as static list of characters with mtg :: ES_ the empty list and mtg :: S_ a non empty list]
[ex: "AB" becomes mtg :: S_< mtg :: Char<'A'>, mtg :: S_< mtg :: Char<'B'>, mtg :: ES_ > > ]
// with mtg :: ES_ and mtg :: S_ defined as:
struct ES_ {};
template<typename hd, typename tl>
struct S_ {}; |
- Type constructor: Constructor ( arguments )
[translate arguments with unique names]
typedef Constructor< [arguments unique names] > name; |
OCaml pervasives type constructors are translated as Metagene pervasives type constructors:
() -> mtg :: Unit
[] -> mtg :: EmptyList
:: -> mtg :: List
True -> mtg :: true_
False -> mtg :: false_ |
- Tuple constructor: ( arguments )
[translate arguments with unique names]
[translate tuple as a static list of arguments with mtg :: EmptyTuple and mtg :: Tuple]
// with mtg :: EmptyTuple and mtg :: Tuple defined as:
struct EmptyTuple {};
template<typename hd, typename tl = EmptyTuple>
struct Tuple {}; |
Scopes, functions and pattern matchings
- Pattern matching: match var with patternlist is seen as (function patternlist) var.
- Function declaration: function patternlist
[Case 1: Only one pattern in patternlist: function x -> expr]
struct name {
template<typename x>
struct value {
[translate expr as "res"]
};
};
[Case 2: Multiple patterns with a default case: function x -> defexpr | pattern1 -> expr1 | pattern2 -> expr2 ...]
struct name {
template<typename x, class _Nil = mtg::nil>
struct value {
[translate defexpr as "res"]
};
template<[translate pattern1 params], class _Nil>
struct value< [translate pattern1 spec], _Nil > {
[translate expr1 as "res"]
};
template<[translate pattern2 params], class _Nil>
struct value< [translate pattern2 spec], _Nil > {
[translate expr2 as "res"]
};
...
};
[Case 3: Multiple patterns without default case]
struct name {
template<typename x, class _Nil = mtg::nil>
struct value {
// res should never be accessed in this version of the template specialization.
};
template<[translate pattern1 params], class _Nil>
struct value< [translate pattern1 spec], _Nil > {
[translate expr1 as "res"]
};
...
}; |
C++ doesn't allow template total specialization in structures, therefore we use only partial specialization thanks to mtg :: nil. (See
Horror Show).
Each pattern is translated into two parts: parameters and specialization. This is detailed in the section concerning patterns.
- Function application: function argument
typedef [typename] function :: value< argument > :: res name; |
The keywork
typename is used when we are inside a class template. If we are inside a struct it is not used.
OCaml pervasives functions are translated as Metagene pervasives functions. All this functions are implemented in Metagene core headers. They correspond to simple well known C++ Metaprograms.
= -> mtg :: equal
<> -> mtg :: notequal
== -> mtg :: eq
!= -> mtg :: noteq
< -> mtg :: lessthan
> -> mtg :: greaterthan
<= -> mtg :: lessequal
>= -> mtg :: greaterequal
compare -> mtg :: compare
+ -> mtg :: addint
- -> mtg :: subint
* -> mtg :: mulint
/ -> mtg :: divint
~- -> mtg :: negint
not -> mtg :: boolnot
or -> mtg :: sequor
|| -> mtg :: sequor
&& -> mtg :: sequand
@ -> mtg :: appendlist
^ -> mtg :: concatstr |
- Let-In declaration: let [rec] decls in expr (seen as let [rec] decls in (let res = expr))
struct [unique_id] {
[translate decls as their own id]
[translate expr as "res"]
};
typedef [unique_id] :: res name; |
C++ constructs seen as values
- C++ Primitive: <@@ arguments @ returntype @ cxxcode @>
struct name {
static returntype value(arguments) {
cxxcode
}
}; |
Miscellaneous
- If-Then-Else: if condition then trueexpr else falseexpr
typedef mtg :: if_<condition, trueexpr, falseexpr>::res name;
// with mtg :: if_ defined as
template<typename condition, typename trueexpr, typename falseexpr>
struct if_ {
typedef falseexpr res;
};
template<typename trueexpr, typename falseexpr>
struct if_<true_, trueexpr, falseexpr> {
typedef trueexpr res;
}; |
- Module access: Module . id
typedef Module :: id name; |
Patterns
As seen in the translation of functions and pattern matching, each pattern is translated into two parts: parameters and specialization.
Simple patterns
parameters: x
specialization: x
// which give us:
template<typename x, class _Nil>
struct value< x, _Nil > {
// ...
}; |
parameters: [none]
specialization: mtg :: Int < intvalue >
// which give us:
template<class _Nil>
struct value< mtg :: Int < intvalue >, _Nil > {
// ...
}; |
parameters: [none]
specialization: mtg :: Char < charvalue > |
parameters: [none]
specialization: [static list of characters, see String Expression] |
- Type constructor: Constructor ( arguments )
parameters: [all parameters of arguments]
specialization: Constructor< [arguments specialization] > |
parameters: [all parameters of arguments]
specialization: [static list of arguments, see Tuple Expression] |
C++ constructs
parameters: [none]
specialization: cxxtype |
- C++ Primitive: <@@ arguments @ returntype @ cxxcode @>
Error: A primitive cannot be matched. |
Miscellaneous
- Pattern Alias: pattern as alias
parameters: [pattern parameters]
specialization: [pattern specialization]
// The alias is handled with a typedef inside the class template specialization:
typedef [pattern specialization] alias; |
Types
Metagene is a typed language whereas the C++ generated meta-code is not. Therefore most of type informations are simply ignored. We only generate empty template and non-template in order to support Variant types. This is required to express Constructor Expressions.
Example: type 'a list =
EmptyList? | List of 'a * 'a list
struct EmptyList {};
template<typename T1, typename T2>
struct List {}; |
Another example: type choice = Yes | No | Maybe
struct Yes {};
struct No {};
struct Maybe {}; |
This corresponds to a common C++ metaprogramming trick.
--
FrancisMaes? - 26 Nov 2003
- Metagene, Metagene main page.
- Introduction, An introduction to the Metagene project.
- History: preliminary examples, Some examples showing the equivalence between C++ meta-programming and functionnal programming.
- History: generation paradigm, The generation paradigm and its history.
- Metagene translation process, From functionnal expressions to class templates.
- Related work, Some related work.
- Download Metagene, Download the latest release of Metagene.
- Paper and Slides, A paper introduicing the Metagene project with corresponding slides.
- Possible extensions, Possible extensions to Metagene.
- Horror Show, The museum of C++ horrors.
to top