This commit is contained in:
2026-09-12 18:12:13 +02:00
parent 18306bdc8c
commit 57ae671f88
27 changed files with 2060 additions and 623 deletions

View File

@@ -49,6 +49,13 @@ wrapToInt32()
En revanche, pour `int32 -> int8`, `tryToInt8()`, `saturateToInt8()` et `wrapToInt8()` ont trois contrats différents et peuvent coexister.
Une règle de composition complète cette non-redondance :
> Deux opérations ne sont fusionnées dans un même nom que si leur séparation en opérations Core successives modifierait la sémantique, perdrait de l'information ou empêcherait d'exprimer le même contrat.
Ainsi `value::floor()::tryToInt32()` rend inutile un alias `tryFloorToInt32()` si les deux formes sont strictement équivalentes.
## A.3. Nomenclature générale
| Code | Famille | Contrat |
@@ -125,16 +132,16 @@ Légende :
|---|---|---|---|---|
| int8 | T | T | T | T |
| int16 | E+R | T | T | T |
| int32 | E+TR+S | E+R | T | T |
| int64 | E+TR+S | E+R | E+R | T |
| int128 | E+TR+S | E+R | E+R | E+R |
| int256 | E+TR+S | E+TR+S | E+R | E+R |
| int32 | E+TR+SR | E+R | T | T |
| int64 | E+TR+SR | E+R | E+R | T |
| int128 | E+TR+SR | E+R | E+R | E+R |
| int256 | E+TR+SR | E+TR+SR | E+R | E+R |
| uint8 | T | T | T | T |
| uint16 | E+TR+S | T | T | T |
| uint32 | E+TR+S | E+R | T | T |
| uint64 | E+TR+S | E+R | E+R | T |
| uint128 | E+TR+S | E+TR+S | E+R | E+R |
| uint256 | E+TR+S | E+TR+S | E+R | E+R |
| uint16 | E+TR+SR | T | T | T |
| uint32 | E+TR+SR | E+R | T | T |
| uint64 | E+TR+SR | E+R | E+R | T |
| uint128 | E+TR+SR | E+TR+SR | E+R | E+R |
| uint256 | E+TR+SR | E+TR+SR | E+R | E+R |
Contrats :
@@ -166,88 +173,128 @@ Légende :
| Source \ Destination | float16 | float32 | float64 | float128 |
|---|---|---|---|---|
| float16 | — | T | T | T |
| float32 | E+TR+S | — | T | T |
| float64 | E+TR+S | E+TR+S | — | T |
| float128 | E+TR+S | E+TR+S | E+TR+S | — |
| float32 | E+TR+SR | — | T | T |
| float64 | E+TR+SR | E+TR+SR | — | T |
| float128 | E+TR+SR | E+TR+SR | E+TR+SR | — |
Règles :
- l'élargissement de format est exact au niveau de la valeur IEEE et utilise uniquement `toFloatXX()` ;
- la réduction de format propose `tryToFloatXX()` pour exiger l'exactitude, `tryRoundToFloatXX()` pour accepter la perte de précision mais pas le débordement fini, et `saturatingRoundToFloatXX()` pour obtenir une opération totale sur le domaine flottant ;
- `NaN`, `+Infinity`, `-Infinity`, `+0` et `-0` restent des catégories IEEE valides dans la destination ;
- pour `NaN`, seule la propriété sémantique `isNaN(destination) == true` est garantie ; payload, signe et quiet/signaling bit ne sont pas garantis par une conversion de valeur ;
- `tryToFloatXX()` accepte `NaN` et les infinities lorsque la destination est un type flottant Saselang, car ces catégories y sont représentables ;
- `saturatingRoundToFloatXX()` ne transforme pas une infinité en valeur finie puisque l'infinité est elle-même représentable dans le format destination ; la saturation explicite concerne les valeurs **finies** hors du domaine fini destination ;
- la conservation exacte du payload binaire d'un `NaN` n'est pas garantie par une conversion de valeur ; elle relève d'un éventuel contrat binaire distinct et de `bitcast` lorsque les tailles sont compatibles.
- la conservation exacte d'une représentation binaire relève d'un contrat binaire distinct et de `bitcast` lorsque ses propres contraintes sont compatibles.
## A.8. Flottant -> entier : inventaire des politiques
## A.8. Flottant -> entier : composition des politiques
Il n'existe jamais de simple `toIntXX()` ou `toUintXX()` depuis un flottant.
La conversion doit annoncer à la fois la politique de passage du réel à l'entier et, lorsque cela est pertinent, la politique de dépassement de domaine.
La conversion stricte canonique est :
### A.8.1. Politique mathématique
| Famille | Sens |
|---|---|
| `Exact` | Accepte uniquement une valeur flottante finie déjà mathématiquement entière. |
| `Floor` | Plus grand entier mathématique inférieur ou égal. |
| `Ceil` | Plus petit entier mathématique supérieur ou égal. |
| `Round` | Nearest, ties to even. |
| `Truncate` | Suppression de la partie fractionnaire, donc direction zéro. |
### A.8.2. Politique de domaine destination
| Politique | Forme | Comportement |
|---|---|---|
| Checked | `try<Policy>ToTarget()` | `Err` sur `NaN`, infinité ou résultat hors plage. |
| Saturating | `trySaturating<Policy>ToTarget()` | `Err` sur `NaN`; les infinités et résultats hors plage saturent aux bornes destination. |
| Wrapping | `tryWrapping<Policy>ToTarget()` | `Err` sur `NaN` et infinité; les résultats entiers finis sont réduits modulo `2^N`. |
La famille complète potentiellement distincte pour une destination entière donnée est donc :
```saselang
value::tryExactToInt32()
value::tryFloorToInt32()
value::tryCeilToInt32()
value::tryRoundToInt32()
value::tryTruncateToInt32()
value::trySaturatingExactToInt32()
value::trySaturatingFloorToInt32()
value::trySaturatingCeilToInt32()
value::trySaturatingRoundToInt32()
value::trySaturatingTruncateToInt32()
value::tryWrappingExactToInt32()
value::tryWrappingFloorToInt32()
value::tryWrappingCeilToInt32()
value::tryWrappingRoundToInt32()
value::tryWrappingTruncateToInt32()
```text
tryToIntXX()
tryToUintXX()
```
La même famille est applicable aux douze destinations entières `int8..int256` / `uint8..uint256` et aux quatre sources flottantes.
Elle réussit uniquement si la valeur flottante est finie, mathématiquement entière, dans le domaine de la destination et exactement représentable comme entier destination. Sinon elle retourne `Err(NumericConversionError(...))`.
Cette section est volontairement exhaustive : lors de la stabilisation Core, certaines combinaisons pourront être supprimées si elles n'apportent aucune valeur pratique ou si une composition Core unique est préférée. Elles ne devront en revanche jamais être remplacées par une opération ambiguë.
### A.8.1. Politiques mathématiques séparées
### A.8.3. Matrice flottant -> entier
Les opérations Core :
Toutes les paires source/destination partagent actuellement le même ensemble de politiques candidates ; la table sert à garantir qu'aucun type n'est oublié.
```text
floor()
ceil()
round()
truncate()
```
restent des opérations sur le flottant et définissent chacune une politique mathématique unique.
Elles se composent ensuite avec les conversions :
```saselang
value::floor()::tryToInt32()
value::ceil()::tryToInt32()
value::round()::tryToInt32()
value::truncate()::tryToInt32()
```
Cette composition remplace les alias redondants `tryFloorTo...`, `tryCeilTo...`, `tryRoundTo...` et `tryTruncateTo...`.
`round()` utilise la règle canonique **nearest, ties to even**.
### A.8.2. Dépassement de domaine
Les politiques de dépassement restent séparées de la politique mathématique.
Pour chaque destination entière, le Core peut exposer :
```text
tryToTarget()
trySaturateToTarget()
tryWrapToTarget()
```
avec les contrats suivants :
| Opération | Préconditions non liées à la plage | Politique de plage |
|---|---|---|
| `tryToTarget()` | valeur finie et mathématiquement entière | `Err` si hors plage |
| `trySaturateToTarget()` | valeur finie et mathématiquement entière | borne à `Target::Min` / `Target::Max` |
| `tryWrapToTarget()` | valeur finie et mathématiquement entière | modulo `2^N` selon le type entier destination |
Les politiques se composent :
```saselang
value::floor()::trySaturateToInt32()
value::round()::trySaturateToUint16()
value::truncate()::tryWrapToInt8()
value::ceil()::tryWrapToUint64()
```
Il n'existe pas de variantes combinées telles que `trySaturatingFloorToInt32()` ou `tryWrappingRoundToInt32()` lorsque la composition ci-dessus possède exactement la même sémantique.
### A.8.3. Matrice flottant -> entier après élimination des doublons
Pour chaque paire, la matrice conserve uniquement les politiques dont le résultat peut réellement différer sur une valeur source admissible.
Légende :
```text
C
tryToTarget() uniquement
CSW
tryToTarget()
trySaturateToTarget()
tryWrapToTarget()
```
| Source \ Destination | int8 | int16 | int32 | int64 | int128 | int256 | uint8 | uint16 | uint32 | uint64 | uint128 | uint256 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| float16 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 |
| float32 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 |
| float64 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 |
| float128 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 | F15 |
| float16 | CSW | CSW | C | C | C | C | CSW | CSW | CSW | CSW | CSW | CSW |
| float32 | CSW | CSW | CSW | CSW | CSW | C | CSW | CSW | CSW | CSW | CSW | CSW |
| float64 | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW |
| float128 | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW | CSW |
`F15` désigne les 15 opérations candidates listées en A.8.2 : 5 politiques mathématiques × 3 politiques de domaine.
Justification :
- toutes les valeurs finies et mathématiquement entières de `float16` tiennent dans `int32` et les entiers signés plus larges ; saturation et wrapping n'apportent donc rien pour ces paires ;
- toutes les valeurs finies et mathématiquement entières de `float32` tiennent dans `int256`, mais pas dans `int128` ou plus petit ;
- pour toute destination non signée, les valeurs négatives rendent checked, saturation et wrapping distincts, même lorsque toute magnitude positive finie tient dans la destination ;
- `float64` et `float128` disposent de valeurs finies dépassant le domaine de tous les entiers Saselang V1.
Cas particuliers :
- `+0` et `-0` produisent l'entier zéro lorsque l'opération choisie réussit ;
- `NaN` n'a jamais de conversion entière implicite ni de valeur saturée/wrappée arbitraire ;
- le wrapping est défini sur le résultat entier mathématique fini après application de `Exact/Floor/Ceil/Round/Truncate` ;
- pour une destination non signée, la saturation d'une valeur négative aboutit à `0` ;
- pour une destination signée, la saturation utilise `Target::Min` / `Target::Max`.
- `+0` et `-0` donnent l'entier zéro ;
- `NaN`, `+Infinity` et `-Infinity` échouent dans ces familles car ils ne satisfont pas la précondition de valeur finie et mathématiquement entière ;
- pour une destination non signée, la saturation d'une valeur négative entière donne `0` ;
- pour une destination signée, la saturation utilise `Target::Min` / `Target::Max` ;
- le wrapping est appliqué au résultat entier mathématique fini selon modulo `2^N`.
## A.9. `bitcast` reste hors de cette matrice
@@ -271,13 +318,15 @@ int32 c = small::toInt32(); // OK
Les membres de conversion appartiennent au Core des primitives. Le compilateur doit pouvoir reconnaître leur contrat via les métadonnées/Core intrinsics nécessaires sans transformer chaque membre en syntaxe spéciale.
Une opération Core peut être :
Pour les conversions fondamentales de cette matrice :
- universelle dans le profil Core minimal ;
- disponible par émulation logicielle même sans instruction machine native ;
- ou conditionnée par une capacité target lorsqu'elle dépend réellement d'une plateforme/backend.
> si les types source et destination sont supportés par le target, les opérations non redondantes définies par la matrice sont Core-required.
Une optimisation matérielle ne constitue pas, à elle seule, une raison de rendre une opération absente : une implémentation logicielle conforme est préférable lorsqu'elle est raisonnable.
L'absence d'une instruction matérielle native ne rend pas l'opération optionnelle lorsqu'une émulation logicielle conforme est raisonnablement possible.
Un target réduit peut ne pas exposer un type fondamental donné. Dans ce cas, l'indisponibilité doit porter sur le type/capacité fondamentale, pas sur une sélection arbitraire de ses conversions.
La nomenclature générale des capabilities et leurs niveaux sont définis au chapitre 40.
## A.12. Hiérarchie documentaire cible
@@ -294,15 +343,40 @@ Saselang Platform Documentation
langage + Core + SDKs + extensions de plateforme
```
À partir de `1.0.0-alpha`, la Bible sera distribuée sous forme d'une archive ZIP structurée avec sommaire, chapitres séparés, exemples/DO-DON'T par chapitre et annexes référencées.
Depuis `0.2.12`, la Bible est distribuée sous forme d'une archive multifichier structurée avec sommaire, chapitres séparés, exemples/DO-DON'T par chapitre et annexes référencées.
## A.13. Points encore à valider
## A.13. `NumericConversionError`
Les points suivants restent volontairement ouverts avant de rendre cette annexe normative :
`NumericConversionError` est le nom de travail du `ResultError` Core des conversions récupérables.
1. confirmer la nomenclature exacte des formes composées `trySaturating...` et `tryWrapping...` pour `float -> integer` ;
2. décider si les 15 opérations `float -> integer` doivent réellement être exposées directement ou si certaines doivent être obtenues par composition d'opérations Core sans créer d'alias sémantique ;
3. préciser le contrat observable des payloads NaN lors des conversions `float -> float` ;
4. définir les codes et informations minimales de `NumericConversionError` ;
5. classer explicitement les capacités numériques en Core minimal obligatoire ou capacité conditionnelle de target.
Les codes sémantiques V1 sont :
```text
NotFinite
NotIntegral
OutOfRange
Inexact
```
L'erreur reste minimale et ne transporte pas automatiquement la valeur source, les types source/destination, le backend, un timestamp ou un mode d'arrondi.
## A.14. État de l'annexe
Les principes sémantiques de la matrice sont désormais largement figés :
```text
non-redondance par paire
composition plutôt qu'alias combinés
règles float -> integer
règles NaN / infinities / signed zero
NumericConversionError
disponibilité Core pour les types supportés
émulation logicielle lorsque raisonnable
```
Restent principalement à auditer lors de l'implémentation Core :
1. le listing mécanique exhaustif des membres concrets exposés par chaque primitive ;
2. les noms définitifs des constantes/membres Core associés ;
3. la représentation interne exacte des codes `NumericConversionError` ;
4. les tests de conformité couvrant toutes les cellules de la matrice.