Templates
Templates Engine Module
Ce module est le moteur de rendu de Raise. Il est responsable de la transformation des modèles de données (JSON/Context) en code source textuel, en utilisant le moteur de template Tera (inspiré de Jinja2). Il assure une stricte séparation entre la logique d’extraction (Générateurs) et la logique de présentation (Templates).
🎨 Architecture et Flux de Données
Le moteur agit comme une “boîte noire” qui prend un nom de template et un contexte de données, applique des transformations typographiques (filtres), et recrache du code.
graph LR
subgraph Input
CTX["Contexte de Données\n(ex: name='cpu_core')"]
TPL_NAME["Nom du Template\n(ex: 'verilog/module')"]
end
subgraph "Template Engine (Tera)"
Lookup[Recherche Template]
Render[Rendu]
subgraph Filters["Filtres Typographiques (Heck)"]
P[PascalCase]
S[snake_case]
C[camelCase]
U[SCREAMING_SNAKE]
end
end
subgraph Output
Code["Code Source Généré\n(String)"]
end
CTX --> Render
TPL_NAME --> Lookup
Lookup --> Render
Render --> Filters
Filters --> Render
Render --> Code
style Filters fill:#f9f,stroke:#333,stroke-width:2px
style Output fill:#bbf,stroke:#333,stroke-width:2px
🛠️ Utilisation Technique
Le TemplateEngine est conçu pour être instancié une seule fois (Singleton pattern recommandé) et partagé entre les générateurs pour éviter de recompiler les templates à chaque appel.
use crate::code_generator::templates::template_engine::TemplateEngine;
use tera::Context;
// 1. Instanciation
let engine = TemplateEngine::new();
// 2. Préparation des données
let mut context = Context::new();
context.insert("name", "flight_controller");
context.insert("id", "FC_001");
// 3. Rendu
let code = engine.render("rust/actor", &context)?;
// Résultat : "pub struct FlightController { ... }"
✨ Filtres Disponibles
Les filtres sont essentiels pour générer du code qui respecte les conventions de chaque langage (ex: une classe en PascalCase mais un fichier en snake_case). Raise intègre la librairie Heck directement dans Tera.
| Filtre | Utilisation dans Template | Entrée | Sortie | Usage Typique |
| ------------------------ | ------------------------- | ------------------------ | -------------- | -------------- | ------------------------------------------------- |
| pascal_case | {{ name | pascal_case }} | my_component | MyComponent | Classes, Structs, Types |
| snake_case | {{ name | snake_case }} | MyComponent | my_component | Variables, Noms de fichiers, Fonctions (Rust/C++) |
| camel_case | {{ name | camel_case }} | MyComponent | myComponent | Variables (JS/TS), Méthodes (Java) |
| screaming_snake_case | {{ name | screaming_snake_case }} | my_var | MY_VAR | Constantes, Macros, Defines |
📚 Catalogue des Templates
Les templates sont actuellement définis dans template_engine.rs (via add_raw_template). Voici la liste des clés disponibles :
Rust
rust/actor: Génère une structure avec dérivation Serde et constructeurnew().
C++
cpp/header: Génère le fichier.hppavec les gardes#pragma onceet la déclaration de classe.cpp/source: Génère le fichier.cppavec l’implémentation des méthodes.
Hardware (FPGA/ASIC)
verilog/module: Génère un module Verilog standard avec entréesclketrst_n.vhdl/entity: Génère uneentityet sonarchitecture Behavioralassociée.
Web / Scripting
ts/class: Génère une classe TypeScript exportée.
📝 Syntaxe des Templates
Nous utilisons la syntaxe Tera (similaire à Django/Jinja2). Exemple de définition de template :
// Entête statique
module {{ name | snake_case }} (
input wire clk,
input wire rst_n
);
/* Description: {{ description | default(value="Aucune description") }}
*/
{% if has_reset %}
always @(negedge rst_n) begin
// Reset logic
end
{% endif %}
endmodule
🚀 Extension future
Actuellement, les templates sont “hardcodés” dans le binaire pour faciliter le déploiement (pas de fichiers externes à gérer). Pour une version future, l’architecture prévoit de :
- Scanner un dossier
assets/templates/. - Permettre à l’utilisateur de surcharger les templates par défaut en déposant des fichiers
.teradans son dossier de configuration.