# 19. Contrôle de flux ## 19.1 `if` / `elseif` / `else` — V1 REQUIS — FIGÉ Les conditions sont obligatoirement de type `bool`. Saselang n'a aucune notion de truthiness/falsiness implicite. Les parenthèses autour de chaque condition et les accolades autour de chaque bloc sont obligatoires, y compris pour un bloc contenant un seul statement. La seule chaîne conditionnelle canonique est : ```text if (condition) { action(); } elseif (otherCondition) { otherAction(); } else { fallback(); } ``` La forme `else if` n'existe pas en Saselang. `elif` n'est pas un alias de `elseif`. Un `if` sans `emit` est uniquement une structure de contrôle et ne produit aucune valeur. Un `if` qui contient `emit` devient un `if` producteur de valeur. Dans ce cas : - le résultat du `if` doit obligatoirement être affecté à une destination ; - un bloc `else` final est obligatoire ; - chaque voie de terminaison normale de chaque branche doit produire explicitement une valeur via `emit` ; - une voie que le compilateur prouve comme terminant définitivement le contrôle (`return`, `throw`, `fault` explicite ou non-terminaison prouvée) n'a pas à exécuter `emit` ; - les valeurs émises doivent être compatibles avec le type de la destination ; - aucune valeur de secours n'est implicite, y compris pour `Option`. Exemple : ```text int32 result = if (x > 10) { emit 1; } elseif (x > 5) { emit 2; } else { emit 3; }; ``` Pour un `Option`, l'absence doit également être explicitement produite : ```text Option result = if (condition) { emit Option::Some(42); } else { emit Option::None; }; ``` Une branche qui termine définitivement le contrôle ne rejoint pas l'affectation de sortie et n'a donc pas à produire de valeur. Cette règle améliore la preuve de contrôle de flux sans introduire de valeur implicite. ## 19.2 `match` — V1 REQUIS — FIGÉ `match` remplace `switch/case` pour la sélection par valeur ou structure. Forme générale : ```text match (value) { pattern1 => { statements; } pattern2 => { statements; } _ => { statements; } } ``` L'expression entre parenthèses est évaluée exactement une fois. Le `match` examine ensuite cette valeur selon les patterns déclarés ; il ne réévalue pas l'expression pour chaque branche. Dans une branche, tout ce qui constitue syntaxiquement le pattern se situe avant `=>`. `=>` est un séparateur grammatical, pas un opérateur. Les patterns d'un même `match` ne doivent pas se chevaucher. Une valeur possible ne peut donc correspondre qu'à une seule branche. L'ordre des branches ne sert pas à résoudre des chevauchements : un chevauchement détectable est une erreur de compilation. Le `match` doit être exhaustif : - si les patterns explicites couvrent toutes les valeurs possibles, une branche finale `_` est interdite car elle serait inaccessible ; - si les patterns explicites ne couvrent pas toutes les valeurs possibles, une branche finale `_` est obligatoire ; - lorsqu'elle existe, `_` est nécessairement la dernière branche. `_` signifie alors « toutes les valeurs restantes non couvertes par les autres patterns ». Il n'existe ni `case`, ni `default`, ni fallthrough. `break` ne sert pas à quitter un `match` ; il reste un contrôle de boucle. Le matching n'exécute pas de code utilisateur caché, de prédicat arbitraire ou de conversion implicite pour décider si une branche correspond. Un pattern décrit directement une valeur, un ensemble de valeurs ou une structure que le compilateur peut examiner à partir de la valeur déjà évaluée. Les classes ne constituent pas des patterns de sélection dynamique. Une relation de sous-typage comme `Dog is Animal` créerait naturellement des ensembles chevauchants et contredirait la règle de non-chevauchement. Les tests dynamiques de classe utilisent `is` avec `if`/`elseif`/`else`. Une classe peut néanmoins être la valeur capturée par un binding lorsque le type statique d'un payload ou d'un champ est déjà cette classe ; cela n'effectue alors aucun test dynamique de classe. ## 19.3 Patterns — V1 REQUIS — FIGÉ EN PRINCIPE Les catégories de patterns déjà figées sont : ```text literal pattern enum variant pattern tuple pattern struct pattern typed binding pattern wildcard _ alternative pattern avec | nested pattern Range pattern si et seulement si le Range est valide selon les règles de Range ``` Les constantes nommées et les détails de compatibilité des littéraux restent à harmoniser avec les règles générales des constantes et des types ; ils ne doivent pas introduire d'évaluation utilisateur cachée. ### 19.3.1 Alternatives avec `|` Dans un pattern, `|` est un séparateur grammatical d'alternatives et non l'opérateur booléen `||` ni l'opérateur bitwise `|`. ```text 1 | 2 | 3 => { ... } ``` Les alternatives d'une même branche doivent elles-mêmes être non chevauchantes, et elles ne doivent chevaucher aucune autre branche. Lorsque des alternatives créent des bindings, toutes les alternatives doivent créer exactement les mêmes bindings, avec les mêmes noms et les mêmes types : ```text A(uint32 value) | B(uint32 value) => { use(value); } ``` est admissible si `A` et `B` sont des variantes distinctes compatibles, alors que les formes où le type ou l'ensemble des bindings change entre alternatives sont interdites. ### 19.3.2 Enum patterns Une variante sans payload peut être utilisée directement : ```text Color::Red => { ... } ``` Une variante avec payload peut contenir des sous-patterns. Une capture est un binding typé explicite : ```text Result::Ok(uint32 value) => { use(value); } Result::Err(Error error) => { handle(error); } ``` La forme `Result::Ok(value)` n'introduit pas implicitement le type de `value` : les variables créées par un pattern respectent la règle générale de typage explicite. `_` peut être utilisé comme sous-pattern pour ignorer explicitement un payload ou un composant : ```text Result::Ok(_) => { ... } ``` ### 19.3.3 Tuple patterns Un tuple peut être décomposé positionnellement en sous-patterns de même arité : ```text (0, 0) => { origin(); } (int32 x, 0) => { horizontal(x); } (int32 x, int32 y) => { other(x, y); } ``` Les bindings sont typés explicitement et leur scope est limité au bloc de leur branche. ### 19.3.4 Struct patterns Un struct se déstructure nominalement par ses champs. Le nom du champ est placé à gauche de `:` et le sous-pattern appliqué à sa valeur à droite : ```text Point { x: 0, y: int32 vertical } => { use(vertical); } ``` Tous les champs du struct doivent être mentionnés exactement une fois dans le pattern. Il n'existe pas de `..` implicite pour ignorer les champs restants. Un champ ignoré doit l'être explicitement avec `_` : ```text Point { x: 0, y: _ } ``` L'ordre des champs n'est pas sémantique puisque les noms les identifient. La destructuration respecte les règles de visibilité normales. `match` ne permet jamais d'accéder à un champ inaccessible depuis le contexte courant. ### 19.3.5 Bindings, scopes et imbrication Un binding créé par un pattern constitue une déclaration locale typée et obéit aux règles normales de non-shadowing. Deux branches différentes peuvent employer le même nom de binding parce que leurs scopes sont disjoints, sauf si un symbole de même nom reste déjà visible depuis un scope englobant. Les patterns sont récursivement imbriquables : tout emplacement qui accepte un sous-pattern peut recevoir un autre pattern compatible avec le type de la sous-valeur. ```text SomeEnum::PointValue( Point { x: 0, y: int32 y } ) => { use(y); } ``` Les classes restent exclues comme test de pattern dynamique, même lorsqu'elles apparaissent comme type statique d'un binding. ### 19.3.6 Guards — REJETÉ Saselang n'ajoute pas de guard `when` ou `if` au pattern. Une condition métier supplémentaire est écrite explicitement dans le bloc de la branche avec le `if` normal. Cela évite d'introduire une deuxième phase de sélection, des chevauchements conditionnels runtime et une complexité supplémentaire dans l'analyse d'exhaustivité. ## 19.4 `emit` dans `if` et `match` — V1 REQUIS — FIGÉ `emit` produit explicitement la valeur de la construction productrice courante sans quitter la fonction. Il est distinct de `return`. Un `if` ou un `match` sans `emit` est une structure de contrôle et ne produit aucune valeur. Dès qu'un `emit` est utilisé dans un `if` ou un `match` : - la construction devient productrice de valeur ; - cette valeur doit obligatoirement être affectée, soit lors d'une déclaration, soit par une affectation à une destination existante ; - toutes les voies de terminaison normale de toutes les branches doivent produire explicitement une valeur compatible avec le type de destination ; - une voie prouvée comme terminant définitivement le contrôle n'a pas à exécuter `emit` ; - aucune valeur n'est produite implicitement. Exemples : ```text int32 result = match (value) { 0 => { emit 10; } _ => { emit 20; } }; ``` ```text int32 result; result = if (condition) { emit 1; } else { emit 2; }; ``` Le rôle du compilateur s'arrête à la validité de l'affectation et du contrôle de flux. Il n'est pas requis que la variable destination soit ensuite effectivement utilisée. ## 19.5 `return`, `break`, `continue`, `yield` — V1 REQUIS / RÉSERVÉ ```text return V1 requis break V1 requis continue V1 requis yield réservé pour generators/coroutines si non finalisé en V1 ``` `break;` et `continue;` sont des statements terminés par `;`. Les labels de boucle ne font pas partie du noyau V1 actuellement retenu. ## 19.6 Boucles — V1 REQUIS — FIGÉ Saselang fournit exactement les formes générales suivantes pour les boucles de base : ```text while (condition) { ... } dowhile (condition) { ... } for (initialization; condition; update) { ... } foreach (Type item in iterable) { ... } ``` Pour toutes ces constructions, les parenthèses d'en-tête et les accolades du corps sont obligatoires. Les conditions de `while`, `dowhile` et `for` sont obligatoirement de type `bool`. `while` évalue sa condition avant chaque itération. `dowhile` exécute le corps au moins une fois puis évalue sa condition après chaque itération, malgré la position syntaxique de la condition avant le bloc : ```text dowhile (condition) { statements; } ``` La forme historique `do { ... } while (...);` n'existe pas. `do` reste `reserved-foreign` et interdit comme identifiant. ### 19.6.1 `for` La condition centrale du `for` est obligatoire. La forme : ```text for (;;) { ... } ``` est interdite. Le compilateur doit orienter vers : ```text while (true) { ... } ``` pour une boucle inconditionnelle. Les zones `initialization` et `update` peuvent contenir plusieurs éléments séparés par des virgules : ```text for (i = 0, j = 5; i < x || j < y; i += 1, j += 1) { ... } ``` Dans ce contexte, la virgule est un séparateur grammatical de la liste d'initialisation ou de mise à jour ; Saselang n'introduit pas d'opérateur virgule général. Les virgules finales restent interdites. La condition centrale reste une seule expression booléenne, même lorsque les zones d'initialisation ou de mise à jour contiennent plusieurs éléments. La liste exacte des formes de statement admises dans les zones d'initialisation et de mise à jour doit rester cohérente avec la grammaire générale des statements ; aucune expression pure ne reçoit implicitement un effet de bord. ### 19.6.2 `foreach` La forme canonique est : ```text foreach (Type item in iterable) { ... } ``` Le type du binding est explicite ; `foreach (item in iterable)` sans type n'est pas admis. `in` est un mot-clé Saselang actif dans cette construction. `foreach` s'appuie sur les interfaces Core `Iterable` / `Iterator`. La variable d'itération appartient au scope du bloc de boucle. ### 19.6.3 Formes redondantes rejetées Saselang n'ajoute pas de synonymes de boucle ou de condition lorsqu'une construction existante exprime déjà la même sémantique : ```text until (...) -> utiliser while (!...) repeat ... until -> utiliser dowhile (!...) unless (...) -> utiliser if (!...) loop { ... } -> utiliser while (true) { ... } ``` Ces mots peuvent rester `reserved-foreign` pour éviter les collisions avec d'autres langages, sans devenir des mots-clés actifs Saselang. ## 19.7 Statements, blocs et terminateurs — V1 REQUIS — FIGÉ Le point-virgule `;` marque exclusivement la fin d'un statement ou d'une déclaration sans corps qui exige un terminateur. Il n'est jamais un séparateur vide ou décoratif. Sont interdits : ```text ; ;; foo();; ``` Une construction terminée par un bloc `{ ... }` ne reçoit pas de `;` supplémentaire. Les accolades ferment déjà le bloc. Les blocs de contrôle utilisent toujours `{ ... }`. Un bloc anonyme à l'intérieur d'une callable suit la même règle et n'est pas suivi de `;`. Les virgules séparent deux éléments ; Saselang n'autorise pas les trailing commas. Ainsi : ```text foo(first, second, third); // valide foo(first, second, third,); // invalide ``` Cette règle vaut pour les listes grammaticales correspondantes : arguments, paramètres, éléments de tuple/array, paramètres génériques et autres listes définies par la grammaire. Les listes spécifiques de `for` suivent la même absence de virgule finale. Les retours à la ligne, espaces, tabs et indentation n'ont aucune signification grammaticale. Hors contenu textuel significatif, une construction peut être placée sur une seule ligne sans changer sa sémantique. ## 19.8 `switch/case` — REJETÉ Pas de `switch/case` C/Java avec fallthrough. `match` couvre la sélection structurelle sans `case`, `default` ni chute implicite.