REPL interactive
Sommaire
- Architecture REPL
- REPL Rust (mode par défaut)
- REPL Python (minimal)
- Lancement
- Commandes REPL
- Editeur de configuration (/config)
- Raccourcis clavier
- REPL Rust (par défaut)
- Interruption d'exécution (Ctrl+C)
- REPL Python (minimal)
- Auto-complétion (REPL Rust)
- Ghost text (REPL Rust)
- Recherche historique (REPL Rust)
- Multiline
- Inspection du contexte (/context)
- Pragmas
- Affichage des résultats
- Choix de la REPL
- Erreur REPL manquante
- Messages d'Erreur
- Syntax highlighting
La REPL Catnip existe en version Rust native intégrée via PyO3, et en version Python pour l'intégration modules.
La REPL s'inscrit dans la tradition Lisp (lecture/évaluation/affichage). Dialogue direct avec le runtime: latence humaine, réponse machine.
Architecture REPL
Catnip fournit deux modes REPL selon le contexte :
REPL Rust (mode par défaut)
TUI ratatui/crossterm dans le crate catnip_repl (_repl.run_repl()) :
- Rapide : startup instantané, exécution native
- Intégrée : aucun binaire externe nécessaire, livré avec
pip install catnip-lang - Optimisé : VM bytecode + JIT intégré
- Config-aware : charge les defaults (
catnip.tomlou built-in), auto-modules (io:!), policies - Source :
catnip_repl/src/(boucle TUI),catnip_repl/src/executor.rs(pipeline)
Le GIL est libéré (py.detach()) pendant la boucle TUI, puis ré-acquis via Python::attach() à chaque exécution de
code.
Utilisé automatiquement pour du Catnip "pur".
REPL Python (minimal)
Wrapper léger MinimalREPL pour intégrer des modules Python (-m/--module) :
- Contexte Python : accès aux modules chargés (
-m math, etc.) - Pipeline complet : parsing → semantic → exécution Python
- Source :
catnip/repl/minimal.py
Activé automatiquement si catnip -m module ou catnip repl -m module.
Lancement
# REPL Rust (par défaut)
catnip # Mode interactif rapide
catnip -v # Mode verbeux
# REPL Python (avec modules)
catnip -m math # Charge module Python, REPL Python
catnip -m math -m numpy # Multi-modules
# Mode pipe (non-interactif)
echo "2+3" | catnip
Commandes REPL
Les commandes commencent par / :
| Commande | Description |
|---|---|
/help |
Afficher l'aide |
/exit, /quit |
Quitter la REPL |
/clear |
Effacer la sortie |
/history |
Afficher l'historique |
/load <file> |
Charger et exécuter un fichier .cat |
/context [var] |
Inspecter les variables utilisateur |
/stats |
Statistiques d'exécution |
/jit |
Activer/désactiver le JIT |
/verbose |
Activer/désactiver le mode verbeux |
/debug |
Activer/désactiver le mode debug |
/time <expr> |
Benchmarker une expression |
/config |
Editeur interactif de configuration |
/version |
Afficher la version |
Note : exit() n'est pas un builtin du langage. Pour quitter la REPL, utiliser /exit, /quit ou Ctrl+D. Pour
terminer un programme depuis le code, utiliser sys = import('sys'); sys.exit(code).
▸ /version
Catnip REPL v0.0.7
Build: release mode
Features: JIT (Cranelift), NaN-boxing VM, Rust builtins
▸ /stats
=== Execution Statistics ===
Variables defined: 0
JIT enabled: yes
JIT threshold: 100
▸ /jit
JIT compiler: disabled
▸ /jit
JIT compiler: enabled
Editeur de configuration (/config)
/config sans arguments ouvre un overlay interactif sous la ligne de prompt. Les clés sont organisées en 6 groupes :
| Groupe | Clés | Persistance |
|---|---|---|
| execution | executor, optimize, tco, jit | catnip.toml |
| display | no_color, theme | catnip.toml |
| cache | enable_cache, cache_max_size_mb, cache_ttl_seconds | catnip.toml |
| debug | log_weird_errors, max_weird_logs, memory_limit | catnip.toml |
| format | indent_size, line_length | catnip.toml |
| repl | show_parse_time, show_exec_time, debug_mode, max_history | session |
Les clés DSL/CLI (groupes execution à format) sont sauvegardées dans catnip.toml immédiatement. Les clés REPL
(groupe repl) sont modifiées en mémoire pour la session courante.
Chaque clé affiche sa valeur courante et sa source (default, file, env, cli, session). Un * marque les valeurs
modifiées par rapport au défaut.
Rendu par type :
- Bool :
on(vert) /off(dim), toggle instantané - Choice :
vm | astavec la valeur courante en gras, cycle au suivant - Int : valeur + range (
0..3) quand sélectionnée, édition inline
Navigation :
| Touche | Action |
|---|---|
| Up / Down / k/j | Naviguer entre les clés |
| Tab | Sauter au groupe suivant |
| Shift+Tab | Sauter au groupe précédent |
| Home / g | Première clé |
| End / G | Dernière clé |
| PageUp/PageDown | Page haut/bas |
| Enter / Space | Toggle (bool), cycle (choice), ou entrer en édition |
| r | Reset au défaut |
| ? | Afficher/masquer l'aide |
| Esc / q / Ctrl+C | Fermer l'éditeur |
Mode édition (valeurs numériques) :
| Touche | Action |
|---|---|
| 0-9 | Saisir la valeur |
| Backspace | Effacer un caractère |
| Left/Right | Déplacer le curseur |
| Enter | Valider (avec borne min/max) |
| Esc / Ctrl+C | Annuler l'édition |
Les sous-commandes textuelles restent disponibles :
/config show: affichage statique (commecatnip config show)/config get KEY: valeur d'une clé/config set KEY VALUE: modifier une clé/config path: chemin du fichier de configuration
Raccourcis clavier
REPL Rust (par défaut)
| Raccourci | Action |
|---|---|
| Ctrl+D | Quitter (ligne vide, sortie normale) |
| Ctrl+C | Interrompre l'exécution en cours, ou annuler/abort sinon |
| Ctrl+R | Recherche inverse dans l'historique |
| Up/Down | Naviguer dans l'historique |
| Ctrl+A / Home | Début de ligne |
| Ctrl+E / End | Fin de ligne |
| Ctrl+U | Effacer la ligne |
| Ctrl+W | Effacer le mot précédent |
| Ctrl+Left/Right | Déplacer par mot |
| Ctrl+L | Effacer l'écran |
| Tab | Déclencher / accepter la complétion |
| Right | Accepter le ghost text (hint) |
| Escape | Fermer le popup complétion |
Interruption d'exécution (Ctrl+C)
Ctrl+C interrompt les exécutions longues. La VM vérifie un flag d'interruption toutes les ~65k instructions. Pendant
l'exécution, un SigintGuard (RAII) ré-active ISIG et installe un handler SIGINT dédié, puis restaure le terminal en
mode raw à la fin.
En dehors d'une exécution (prompt de saisie), Ctrl+C annule la ligne courante ou quitte la REPL si la ligne est vide.
REPL Python (minimal)
La REPL Python minimale offre une interface simplifiée :
| Raccourci | Action |
|---|---|
| Ctrl+D | Quitter (ligne vide, sortie normale) |
| Ctrl+C | Annuler la saisie courante, ou abort si vide |
Pas d'auto-complétion ni de recherche historique avancée : priorité à la compatibilité Python.
Auto-complétion (REPL Rust)
Tab ouvre un popup de complétion contextuelle. Chaque suggestion est catégorisée :
| Catégorie | Contenu |
|---|---|
variable |
Variables définies dans le contexte courant |
keyword |
Mots-clés du langage (if, while, match) |
builtin |
Fonctions builtin (générées depuis context.py) |
command |
Commandes REPL (/help, /exit, /stats) |
method |
Méthodes/attributs après . |
Après un ., le compléteur utilise dir() sur la variable pour proposer ses attributs réels. Par exemple,
io = import('io') puis io. propose les attributs du module io. Les instances de struct exposent leurs champs et
méthodes : p = Point(1, 2) puis p. propose x, y et les méthodes définies. Si la variable n'est pas connue,
fallback sur les méthodes hardcodées de str, list et dict.
Priorité : variables > keywords > builtins (évite le shadowing accidentel).
Navigation : Tab/Down = suivant, Shift+Tab/Up = précédent. Si plus de 8 suggestions, un indicateur de scroll
(offset/total) apparaît.
Ghost text (REPL Rust)
En plus du popup (Tab), la REPL affiche un ghost text grisé après le curseur. Le texte apparaît pendant la saisie et se valide avec la flèche droite.
Trois contextes de suggestion :
- Appel de fonction :
map(fn, |afficheiterable)(paramètres restants) - Mot-clé :
whi|affichele condition { body }(template de structure) - Identifiant :
pri|affichent(values...)(complétion + signature)
Le ghost text et le popup de complétion sont mutuellement exclusifs : Tab ouvre le popup et masque le ghost text, Escape ferme le popup et restaure le ghost text.
Le ghost text connaît les 28 signatures builtin et les 8 templates de mots-clés. Il connaît aussi les variables définies dans le contexte courant, ce qui lui confère une omniscience locale dont il use avec modération.
Recherche historique (REPL Rust)
L'historique est persistant dans $XDG_STATE_HOME/catnip/repl_history (par défaut
~/.local/state/catnip/repl_history).
Recherche inverse (Ctrl+R) : ouvre un prompt de recherche dans l'historique, similaire à fish/bash. Taper du texte filtre les entrées correspondantes. Ctrl+R cycle vers le résultat suivant, Enter accepte la sélection, Escape annule et revient au prompt normal.
Multiline
La REPL détecte automatiquement les expressions multilignes :
- Délimiteurs non fermés (
{,(,[) - Opérateurs en fin de ligne (
+,-,*, etc.) - Mots-clés de contrôle (
if,while,for, etc.)
La continuation est automatique : Enter ajoute une nouvelle ligne tant que l'expression est incomplète, et soumet quand elle est complète. Les nouvelles lignes sont auto-indentées selon le niveau d'imbrication courant (accolades, parenthèses, crochets).
▸ f = (x) => {
x * 2
}
▸ f(21)
42
Inspection du contexte (/context)
/context affiche les variables définies par l'utilisateur avec leur type et valeur tronquée. /context <var> affiche
le détail complet d'une variable.
▸ x = 42
▸ name = "Alice"
▸ /context
=== Context ===
name str 'Alice'
x int 42
▸ /context x
x: int = 42
Les variables builtins et internes (préfixées _) sont exclues de l'affichage.
Pragmas
Les directives pragma fonctionnent dans les deux REPL. L'état des pragmas persiste entre les évaluations :
▸ pragma("jit", True)
▸ pragma("tco", False)
▸ # Les pragmas restent actifs pour les évaluations suivantes
Les pragmas s'appliquent au contexte d'exécution immédiatement. La precedence reste : CLI > REPL > Défaut.
Affichage des résultats
La REPL affiche automatiquement le résultat de chaque expression évaluée. Les résultats None sont supprimés, comme en
Python :
▸ 42
42
▸ "BORN TO SEGFAULT"
BORN TO SEGFAULT
▸ x = 10
10
▸ while (False) { 1 }
▸ # Pas d'affichage (None supprimé)
En mode verbose (-v), None reste visible dans le stage RESULT pour le debug.
Choix de la REPL
La CLI détecte automatiquement quelle REPL utiliser :
# REPL Rust (standalone)
catnip # Aucun module → REPL Rust
catnip -o jit script.cat # Pas de -m → REPL Rust si erreur
# REPL Python (wrapper)
catnip -m math # -m présent → REPL Python
catnip -m math -m numpy # idem
Règle : Présence de -m/--module déclenche REPL Python (accès contexte modules). Sinon, REPL Rust (standalone).
Erreur REPL manquante
Depuis l'intégration PyO3, la REPL Rust est incluse dans l'extension _rs.so compilée avec make compile. Aucun
binaire externe n'est requis.
Si la REPL n'est pas disponible (extension non compilée) :
Error: Rust REPL not available
Install it with: make compile
Solution : recompiler l'extension Rust :
make compile
# ou
make setup
Le binaire standalone
catnip-replexiste toujours comme fallback (si_repl.run_repléchoue), mais il n'est plus nécessaire en usage normal.
Messages d'Erreur
Les erreurs runtime affichent la position source avec pile d'appels :
▸ f = (x) => { x / 0 }
▸ f(42)
File '<repl>', line 2, column 6: division by zero
2 | f(42)
| ^
Traceback (most recent call last):
File "<repl>", in <lambda>
CatnipRuntimeError: division by zero
Format : fichier, ligne, colonne, snippet avec caret, traceback montrant la chaîne d'appels.
Continuer après erreur : La REPL reste ouverte, les variables définies avant l'erreur restent accessibles.
Syntax highlighting
Le highlighter utilise tree-sitter pour coloriser le code en temps réel :
| Element | Couleur | Style | Exemples |
|---|---|---|---|
| Keywords | Cyan | Bold | if, while, for, match, return |
| Constants | Purple | Bold | True, False, None |
| Built-in types | Blue | - | dict, list, set, tuple |
| Numbers | Yellow | - | 42, 3.14, 0xFF |
| Strings | Green | - | "hello", f"x={x}" |
| Comments | Dark gray | - | # comment |
| Operators | Red | - | +, -, ==, => |
| Builtins | Blue | - | print, len, type, range |
| Punctuation | White | - | (, ), [, ], {, } |
| Identifiers | Default | - | Variables et fonctions |
Les noeuds ERROR (code incomplet) sont aussi traversés pour que le highlighting fonctionne pendant la saisie.