Glossaire Catnip

Ce document définit les concepts clés et la terminologie utilisée dans le projet Catnip, afin d'éviter les ambiguïtés dans la documentation.

Architecture et Composants

HostApp (Application Hôte)

L'application hôte est le programme Python qui intègre et utilise Catnip comme langage embarqué. Elle fournit:

  • Le contexte d'exécution
  • Les fonctions et objets Python accessibles depuis Catnip
  • L'environnement d'intégration

Exemple: Une application web Flask qui utilise Catnip pour les scripts de configuration utilisateur.

Runtime

L'ensemble des composants nécessaires à l'exécution du code Catnip:

  • Parser
  • Semantic analyzer
  • Registry
  • Executor
  • Context

Registry

Le registre est le composant central qui:

  • Gère le mapping entre opérations (opcodes) et leurs implémentations
  • Maintient le contexte d'exécution (scopes, variables)
  • Fournit l'interface entre l'AST et les opérations concrètes

Modules: registry.py, core/registry_core.pyx

Context

Le contexte d'exécution contient:

  • Les scopes (portées) avec leurs variables locales/globales
  • Le résultat de la dernière expression
  • L'accès aux builtins Python
  • L'état d'exécution (pile de scopes)

Fichier: catnip/context.py

Phases d'Exécution

Parsing

Transformation du code source Catnip en Abstract Syntax Tree (AST) via Lark.

Parser utilisé : Earley (gère les ambiguïtés, flexible mais lent)

Composants:

  • parser.py: Classe Parser basée sur Lark
  • grammar.lark: Grammaire du langage
  • transformer/: Transformation de l'arbre Lark en IR

Performance : Le parsing Earley est relativement lent. Le cache est essentiel en production.

Semantic Analysis

Transformation de l'AST en Op nodes (opérations exécutables):

  • Résolution des références
  • Optimisation (constant folding, etc.)
  • Détection des tail-calls
  • Application des pragmas

Module: catnip/semantic/analyzer.py

Execution

Exécution des Op nodes via le Registry, par interprétation directe de l'arbre.

Module: executor.py

OpCode

Code d'opération numérique (enum) utilisé pour identifier les opérations de manière efficace.

Avantages : - Comparaisons O(1) (entiers vs strings) - Lookups rapides dans les dictionnaires - Moins de mémoire - Unifié : IR et Op utilisent le même enum

Exemples :

OpCode.ADD = 1
OpCode.SUB = 2
OpCode.OP_IF = 10     # Préfixe OP_ pour mots-clés Cython
OpCode.OP_WHILE = 11

Convention : Les opcodes correspondant à des mots-clés Cython (if, while, for, etc.) sont préfixés par OP_.

Module : catnip/semantic/opcode.py

Trampoline

Technique d'optimisation TCO qui transforme les appels récursifs en une boucle avec rebinding de paramètres.

Principe : Au lieu d'empiler des frames, la fonction retourne un signal TailCall qui indique au trampoline de rebinder les paramètres et recommencer.

Résultat : O(1) stack space au lieu de O(n).

La fonction rebondit sur elle-même sans jamais vraiment s'appeler.

Structures de Données

IR (Intermediate Representation)

Nœud intermédiaire produit par le transformer:

IR(ident=OpCode.ADD, args=(left, right), kwargs={})

Op (Operation)

Nœud exécutable produit par l'analyse sémantique:

Op(ident=OpCode.ADD, args=(left, right), kwargs={})

Points communs : IR et Op utilisent le même enum OpCode pour identifier les opérations.

Différence : IR est la sortie brute du parser (avant optimisation), Op est optimisé et annoté (tail calls, etc.).

Scope (Portée)

Une portée est un dictionnaire de symboles (variables) avec un parent optionnel:

  • Global scope: Portée racine
  • Local scope: Portée créée par fonction/lambda/bloc
  • Lookup: Recherche en cascade (local → parent → global)

Module: core/scope.pyx (optimisé Cython)

Node

Classes pour les objets Catnip exécutables:

  • Op: Nœud d'opération (cdef class Cython)
  • IR: Nœud intermédiaire (hérite de Op)
  • Function: Fonction nommée (cdef class Cython)
  • Lambda: Fonction anonyme (cdef class Cython)
  • Pattern*: Patterns de pattern matching

Module: core/op_core.pyx (Op), core/nodes_core.pyx (Function, Lambda), nodes.py (réexports et autres)

Optimisations

TCO (Tail-Call Optimization)

Optimisation des appels terminaux: Les fonctions qui se terminent par un appel récursif sont optimisées pour ne pas consommer de stack Python.

Implémentation: Trampoline pattern avec détection de self-recursion.

Pragma: pragma("tco", True) / pragma("tco", False)

Constant Folding

Résolution anticipée: Les expressions constantes sont évaluées au moment de l'analyse sémantique plutôt qu'à l'exécution.

Exemple: 2 + 3 * 414 (au parse-time)

Cython Optimization

Modules critiques implémentés en Cython pour performance maximale:

  • core/: Modules core (scope, registry, nodes, broadcast)
  • transformer/: Transformation parse tree → IR
  • semantic/: Analyse sémantique et optimisations

Strength Reduction

Réduction de force : Remplacement d'opérations coûteuses par des équivalentes moins coûteuses.

Exemple : x ** 2x * x (multiplication plus rapide que puissance)

Dead / Blunt Code Elimination

Élimination de code mort : Suppression du code inaccessible ou jamais exécuté.

Exemple : if (true) { a } else { b }{ a } (branche else supprimée)

Pragmas

Pragma

Directive de compilation qui contrôle le comportement du compilateur/runtime.

Syntaxe: pragma("directive", value) où value peut être un booléen, string ou nombre

Directives supportées:

  • tco: Tail-call optimization (True/False)
  • optimize: Niveau d'optimisation (0-3 ou "none"/"full")
  • cache: Cache de parsing (True/False)
  • debug: Mode debug (True/False)
  • feature: Charger un module Catnip ou Python (pur ou binaire) par nom ou chemin (pragma("feature", "module", "alias"))

Exemples:

pragma("tco", True)
pragma("optimize", "3")
pragma("feature", "json")
pragma("feature", "pandas", "pd")
pragma("feature", "./toolbox.cat", "tools")

Module: pragma.py

Pattern Matching

Pattern

Structure utilisée pour le matching dans match/case:

  • PatternLiteral: Match une valeur exacte (1, "text")
  • PatternVar: Capture la valeur dans une variable (x)
  • PatternWildcard: Match tout (_)
  • PatternOr: Match une alternative (a | b | c)

Guard

Condition ajoutée à un pattern: n if n > 10

Fonctions et Lambdas

Function (Fonction Nommée)

Fonction définie avec un nom:

factorial = (n) => { … }

Lambda (Fonction Anonyme)

Fonction sans nom, souvent inline:

numbers.[() => { x * 2 }]

Variadic Parameters

Paramètres qui acceptent un nombre variable d'arguments:

sum = (*args) => { … }

Syntaxe: Préfixe * devant le nom du paramètre.

Closure (Fermeture)

Fonction qui capture les variables de son scope parent.

Exemple :

make_adder = (n) => {
    (x) => { x + n }  # Capture 'n' du scope parent
}

add5 = make_adder(5)
add5(10)  # → 15

Unpacking (Destructuring)

Décomposition d'une structure de données en plusieurs variables.

Syntaxe :

(a, b) = tuple(1, 2)
(first, *rest) = list(1, 2, 3, 4, 5)
(x, (y, z)) = list(1, tuple(2, 3))

Support : Tuples, listes, imbrication, star operator (*)

Broadcasting

Broadcasting Operation

Application d'une opération, étendue naturellement à toutes les dimensions internes.

La même expression fonctionne quel que soit le "niveau" : scalaire, liste, matrice, colonne, tenseur, ou structure hôte arbitraire.

Syntaxe: collection.[operation]

Types:

  • Binaire: .[+ 10], .[* 2]
  • Unaire: .[abs], .[not]
  • Fonction: .[(x) => { x ** 2 }]
  • Filtre: .[(x) => { x % 2 == 0 }]

Catnip applique toujours l’opération "au bon endroit"”", même quand la dimension n’est pas connue à l’avance.

Termes Généraux

Builtin

Fonction ou objet Python accessible depuis Catnip sans import.

Exemples: range, list, dict

Pure Function

Fonction sans effets de bord qui retourne toujours le même résultat pour les mêmes arguments.

Utilisé pour: Optimisations de broadcasting, mémoization.

Décorateur : @pure en Python

Tail Position

Une expression est en position terminale si sa valeur est immédiatement retournée sans autre calcul.

Important pour: TCO (Tail-Call Optimization)

Cache

Système de mémorisation pour éviter de re-parser ou re-compiler du code déjà traité.

Types :

  • Parse cache : Cache des AST parsés (évite le parsing)
  • Compilation cache : Cache des Op nodes compilés
  • Function cache : Mémoization des résultats de fonctions pures

Backends : Mémoire, disque, Redis

Activation :

catnip = Catnip(enable_cache=True)

Pragma :

pragma("cache", True)

Module : cachesys.py

Sandbox (Bac à sable)

Environnement d'exécution isolé qui limite les actions possibles du code.

Objectif : Permettre l'exécution de code utilisateur sans risque pour le système hôte.

Catnip peut s'exécuter dans un contexte restreint où seules certaines fonctions Python sont accessibles.

Fichiers et Structure

.cat

Extension de fichier pour les scripts Catnip.

Interfaces et Outils

REPL (Read-Eval-Print Loop)

Mode interactif de Catnip accessible via catnip sans arguments.

Fonctionnalités :

  • Lecture d'une expression utilisateur
  • Évaluation immédiate
  • Affichage du résultat
  • Contexte persistant entre les commandes

Exemple :

$ catnip
🌿> x = 10
🌿> x * 2
20
🌿> factorial = (n) => { if (n <= 1) { 1 } else { n * factorial(n-1) } }
🌿> factorial(5)
120

Fichier : __main__.py

CLI (Command Line Interface)

Interface en ligne de commande pour exécuter Catnip.

Modes d'exécution :

  • Script : catnip script.cat (fallback automatique)
  • Script explicite : catnip -- script.cat (avec séparateur)
  • Commande : catnip -c "expression"
  • Pipe : echo "2 + 3" | catnip
  • REPL : catnip (interactif, défaut)
  • Sous-commandes : catnip format script.cat, catnip check script.cat (futur)

Options :

  • -c, --command : Exécute une commande unique
  • -p, --parsing : Niveau de parsing (0-3)
  • -o, --optimize : Options d'optimisation (ex: tco:on)
  • -l, --load : Charge un module Python
  • --as : Nom personnalisé pour le module
  • --inject : Injecte les fonctions directement dans globals

Exemples :

catnip script.cat              # Exécute (fallback)
catnip -- script.cat           # Exécute (explicite)
catnip -c "2 + 3"              # Évalue
catnip -o tco:on script.cat    # Avec TCO
echo "10 * 2" | catnip         # Depuis stdin
catnip format script.cat       # Sous-commande (futur)

Séparateur -- : Force l'interprétation de l'argument suivant comme un fichier, levant toute ambiguïté avec les sous-commandes.

Fichier : __main__.py

JIT (Just-In-Time Compilation)

Compilation à la volée du code Catnip (fonctionnalité expérimentale).

État actuel : Partiellement implémenté, pas encore de gestion de cache intégrée.

Activation :

ctx.jit_enabled = True

Pragma :

pragma("jit", True)

Objectif : Compiler les fonctions fréquemment appelées en bytecode optimisé pour améliorer les performances d'exécution.

Le JIT détecte les hot paths et les compile. Actuellement, il ne cache pas encore les compilations, ce qui limite son efficacité.

Acronymes

  • AST: Abstract Syntax Tree (Arbre Syntaxique Abstrait)
  • IR: Intermediate Representation (Représentation Intermédiaire)
  • TCO: Tail-Call Optimization (Optimisation des Appels Terminaux)
  • VM: Virtual Machine (Machine Virtuelle)
  • REPL: Read-Eval-Print Loop (Boucle Lecture-Évaluation-Affichage)
  • CLI: Command Line Interface (Interface en Ligne de Commande)
  • JIT: Just-In-Time Compilation (Compilation à la Volée)
  • Op: Operation (Opération exécutable)
  • CSE: Common Subexpression Elimination (Élimination des Sous-Expressions Communes)

Conventions de Nommage

Fonctions Internes

  • Préfixe _: Fonction privée (ex: _execute())
  • Préfixe visit_: Méthode de visitor pattern (ex: visit_if())
  • Préfixe exec_: Méthode d'exécution (ex: exec_stmt())

Modules Cython

  • Suffixe _core: Module core optimisé (ex: nodes_core.pyx)
  • Suffixe _opt: Module optimisé (ex: semantic_opt/)

Classes

  • PascalCase: PatternLiteral, Function, Lambda
  • Suffixe Mixin: Classe mixin (ex: ControlFlowMixin)

Relations Entre Concepts

HostApp
  └─> Runtime
       ├─> Parser
       │     └─> IR(OpCode) - sortie du transformer
       ├─> Optimizer
       │     └─> IR optimisé
       ├─> Semantic Analyzer
       │     └─> Op(OpCode) - nœuds exécutables
       └─> Executor
             ├─> Registry (résolution des opérations)
             └─> Context (scopes, variables, fonctions, JIT, cache)

Exemples d'Usage

Intégration dans une HostApp

from catnip import Catnip

# Créer l'interpréteur
cat = Catnip()

# Injecter des objets Python
cat.context.locals['db'] = my_database
cat.context.locals['config'] = app_config

# Exécuter du code Catnip
result = cat.parse('db.query("SELECT * FROM users")').execute()

Pragma

pragma("tco", True)
pragma("optimize", "3")
pragma("feature", "json")

factorial = (n, acc=1) => {
    if n <= 1 { acc } else { factorial(n - 1, n * acc) }
}

# Utiliser le module chargé
data = dict(("x", 10))
json_str = json.dumps(data)

Broadcasting

numbers = list(1, 2, 3, 4, 5)
doubled = numbers.[* 2]        # [2, 4, 6, 8, 10]
squares = numbers.[(x) => { x ** 2 }]  # [1, 4, 9, 16, 25]