LEÇON 18 / 60 minutes

Lire les limites du compilateur

Pour écrire du Vitte utilisable, il faut savoir où vérifier une construction — dans la grammaire, l’analyseur, le typage ou l’exécution. Cette dernière leçon vous apprend à suivre une fonctionnalité jusqu’à la preuve disponible.

À retenir·Une forme écrite dans la grammaire ne garantit pas qu’elle compile ni qu’elle s’exécute dans chaque chemin du compilateur.

Quatre niveaux de preuve pour chaque construction

Une syntaxe ne se résume pas à son appartenance au langage. Dans le dépôt Vitte, sa prise en charge se décrit à quatre niveaux complémentaires :

  1. Grammaire. Une règle EBNF indique la forme prévue du code.
  2. Analyse syntaxique. Le parseur reconnaît cette forme et construit une représentation.
  3. Analyse sémantique. Les noms, les types et les contraintes sont vérifiés.
  4. Génération et exécution. Le backend produit un exécutable qui fournit un résultat observable.

Ces preuves ne sont pas interchangeables. Une page de grammaire décrit la syntaxe ; une commande de parsing confirme la structure ; un exécutable réussi confirme un cas précis sur un chemin de compilation donné.

Comparer des niveaux de preuve

La matrice du projet donne des exemples concrets. Une boucle while apparaît dans les tests runtime ; le compilateur natif la prend donc en charge dans les cas couverts. La déclaration d’une form non générique et le choix pick avec charge utile sont également exercés jusqu’à l’exécution.

À l’inverse, le test dédié d’une forme générique arrive jusqu’au backend, puis reçoit un diagnostic de génération de code. La forme for sur tableau atteint elle aussi une erreur backend dans le test ciblé. Ces exemples ne signifient pas que toute la syntaxe correspondante est inconnue : ils indiquent précisément que le chemin de compilation testé n’achève pas ces cas.

Consultez l’état du support Vitte avant de bâtir un projet sur une construction avancée. La matrice détaille aussi les différences entre le frontend natif et le chemin de compatibilité.

Explorer une source avec la CLI

Depuis la racine du dépôt, la CLI permet d’inspecter différentes étapes :

build/bin/vitte lex examples/tutorials/syntaxe.vit
build/bin/vitte parse examples/tutorials/syntaxe.vit
build/bin/vitte check examples/tutorials/syntaxe.vit
build/bin/vitte run examples/tutorials/syntaxe.vit --quiet --no-color

lex montre les tokens ; parse vérifie la structure ; check poursuit l’analyse ; run demande la compilation et l’exécution. Pour examiner une étape intermédiaire d’une compilation, la commande documentée accepte aussi compile fichier.vit --stop-after-sema. La disponibilité d’une option ne garantit pas la prise en charge de chaque syntaxe : notez la commande et son résultat exact.

Réduire un problème à son plus petit exemple

Si un programme ne passe pas, enlevez temporairement tout ce qui n’est pas nécessaire au diagnostic. Gardez une seule déclaration, une procédure courte et la construction en question. Les étapes de diagnostic sont les suivantes :

  1. Vérifiez que le fichier et la commande ciblent bien le même frontend.
  2. Le parseur permet de séparer un problème de syntaxe d’un problème plus loin dans le pipeline.
  3. Lisez le code de diagnostic et l’emplacement, puis corrigez une seule cause.
  4. Lorsque le parsing et l’analyse passent mais que la génération échoue, la comparaison avec un exemple compilé du même type de construction précise la limite.
  5. Ajoutez le cas réduit aux notes de projet avec la version de l’outil et le résultat observé.

Une erreur backend n’est pas la preuve que votre syntaxe est mal écrite. Un diagnostic de type ne se corrige pas nécessairement en changeant la grammaire. Identifier la phase vous permet de chercher au bon endroit.

Ne pas transformer un cas réussi en promesse générale

Si while fonctionne dans un exemple, cela confirme les opérations exercées dans cet exemple : la condition, le corps, les mises à jour et la sortie testée. Cela ne prouve pas automatiquement que toutes les formes de boucle, tous les types d’indice ou toutes les cibles d’exécution se comportent de la même façon.

Utilisez la même précision quand vous écrivez de la documentation. Indiquez la source, la commande, le résultat et le mode de compilation. Si aucun test ne couvre le cas exact, dites qu’il reste à confirmer. Une limite documentée est plus utile qu’une promesse fondée uniquement sur la grammaire.

Tenir un carnet de vérification Vitte

Lorsqu’une construction importante entre dans votre projet, gardez une fiche que vous pouvez relire après une mise à jour du compilateur :

Construction : import d'un module avec alias
Version et commit : à renseigner
Commande : VITTE_MODULE_PATH=examples build/bin/vitte run ...
Analyse : réussie dans l'exemple ciblé
Compilation : exécutable produit par le frontend natif
Exécution : code de sortie 0
Limite : preuve valable pour les deux modules de la fixture

La fiche nomme le périmètre de la preuve. Elle permet de distinguer une supposition, une règle de grammaire et une commande réellement exécutée. Lorsqu’un test échoue après une mise à jour, vous savez quelle étape comparer au résultat précédent.

Lire les diagnostics sans les confondre

Un code d’erreur peut indiquer la phase qui a refusé le programme. Une erreur lexer ou parser signale souvent qu’une forme n’a pas été reconnue. Une erreur de type signifie que le programme a dépassé ces étapes, mais que les valeurs ou opérations ne concordent pas. Un diagnostic backend peut apparaître après que la syntaxe et une partie de l’analyse ont réussi, lorsque le compilateur ne sait pas produire le code final.

Dans tous les cas, conservez la commande et le fragment minimal. Ne corrigez pas un rejet backend en réécrivant la ponctuation au hasard ; cherchez une forme déjà compilée qui répond au même besoin ou reporte la dépendance.

Établir la source d’autorité

Pour le langage, commencez par la grammaire canonique et la spécification. Pour une capacité d’un frontend, cherchez son test de parité ou d’analyse. Pour une affirmation runtime, recherchez le programme et la commande qui le lancent. Si plusieurs documents du dépôt se contredisent, notez la divergence et privilégiez le test ciblé le plus proche de la construction que vous souhaitez utiliser.

Une fixture négative est une preuve utile elle aussi : elle indique précisément une limite. Par exemple, le test d’une forme générique rejetée au backend permet d’enseigner la syntaxe et le modèle de type tout en avertissant que ce cas ne fournit pas un exécutable natif.

Faire une enquête reproductible

  1. La fiche identifie une construction Vitte et le comportement attendu.
  2. Le fichier minimal ne contient que les déclarations et dépendances nécessaires.
  3. Les étapes s’enchaînent dans l’ordre : tokens, analyse syntaxique, vérification, compilation, exécution.
  4. La sortie de chaque étape identifie la première qui échoue.
  5. La comparaison avec un exemple positif ou négatif du dépôt précise la différence observée.

Si la CLI n’expose pas une étape ou si une sortie est ambiguë, réduisez encore le cas et consultez la documentation de la commande. Le but est de produire une observation que quelqu’un d’autre peut répéter, pas de confirmer l’idée que l’on avait avant l’essai.

Exemple de compte rendu précis pour « cette fonctionnalité fonctionne-t-elle ? »

« La grammaire la décrit ; le test ciblé passe l’analyse ; la compilation atteint le backend puis est rejetée avec VITTE_BACKEND_E_CODEGEN ; aucun runtime n’est donc établi pour ce cas. » Cette réponse est plus précise qu’un oui/non et vous aide à décider ce qui peut entrer dans votre programme.

Fin du parcours approfondi

Le parcours relie la lecture du code Vitte, le raisonnement sur les valeurs et les états, l’organisation des modules et la vérification de la prise en charge. La référence et les fixtures du dépôt détaillent chaque construction à partir de ses sources.

Une échelle de preuves pour chaque fonctionnalité

La preuve la plus faible est une forme présente dans une grammaire : elle établit que la syntaxe est décrite. Le parsing montre que le lexer et le parseur reconnaissent une source donnée. La vérification sémantique montre que les noms et contraintes passent les analyses exécutées. La génération réussie indique que le backend a produit une sortie pour ce cas. L’exécution contrôlée établit enfin un résultat observable. Ces niveaux s’accumulent, mais aucun ne doit être remplacé par le précédent.

Une preuve runtime n’est pas universelle. Elle dépend du frontend, de la version, du backend, des paramètres et du scénario de la fixture. Un exemple de while qui s’exécute confirme la boucle testée et ses opérations, mais ne confirme pas chaque combinaison de contrôle, type ou cible. Les cas négatifs comptent autant : VITTE_BACKEND_E_CODEGEN est une observation précise du rejet au backend, pas une erreur de grammaire.

Lire la chaîne de compilation sans confondre les commandes

lex, parse, check, compile et run suivent différents niveaux du processus. Une commande peut s’arrêter après l’analyse sémantique ; une autre peut demander de produire et de lancer le programme. Les options de diagnostic changent la façon dont les messages sont présentés, non la garantie qu’une construction est prise en charge. La commande exacte est donc une partie du résultat documenté.

Lorsque la première étape qui échoue est connue, la recherche devient plus ciblée. Une erreur de parsing conduit à la grammaire et à la ponctuation. Une erreur de nom conduit aux déclarations, imports et visibilités. Une erreur de type conduit aux opérandes et signatures. Une erreur de génération conduit au backend, à son codegen et aux tests de parité. Récrire toute la source sans cette distinction peut masquer la phase responsable sans apporter de preuve nouvelle.

Documenter un résultat reproductible

Une fiche de support complète conserve la construction examinée, le fichier source, la version ou le commit, la commande et le code de sortie. Elle note aussi la première phase qui échoue, le diagnostic exact et la cible utilisée. Si un programme s’exécute, la sortie et le comportement observé font partie du constat. Si le test est négatif, le code non nul est attendu et doit être associé au diagnostic précis.

Cette méthode permet de comparer le dépôt avant et après une évolution du compilateur. Une fixture positive peut changer de résultat ; une fixture négative peut passer après une correction ; un nouveau frontend peut ajouter une autre voie. La documentation conserve alors une observation datée et révisable, au lieu d’un jugement global sur une fonctionnalité. La matrice de support de Vitte applique précisément cette distinction entre grammaire, analyse, compilation et exécution.

Maintenir une matrice de support utile

Une matrice devient pratique lorsque chaque ligne correspond à une construction et chaque colonne à une étape observable : grammaire, parsing, analyse, génération et runtime. Le statut doit citer un test ou une source et préciser le frontend. Des catégories telles que « supporté » ou « en cours » sont trop générales si elles ne disent pas quelle combinaison a été essayée.

Une seule construction peut avoir plusieurs résultats selon son contexte. Un paramètre générique sans opération, une forme générique composée et un trait avec implémentation sont trois cas différents. Un tableau parcouru avec une boucle while et le même tableau parcouru avec for sont également différents du point de vue du backend. Des fixtures étroites empêchent de généraliser le résultat d’un cas à tous les autres.

Signification d’une progression de diagnostic

Si un fichier passe du parseur à l’analyse sémantique, puis au backend avant un rejet, la progression donne une information positive sur les phases antérieures. Elle ne garantit pas que la sémantique est complète pour toutes les formes associées, mais elle précise que le problème n’est pas simplement une ponctuation non reconnue. Le code d’erreur, tel que VITTE_BACKEND_E_CODEGEN, nomme la première étape observée qui ne peut pas achever le cas.

Après une mise à jour, le même fichier peut échouer plus tôt, plus tard ou réussir. La comparaison des diagnostics signale alors une régression, un changement de phase ou une amélioration. Conserver les cas positifs et négatifs dans le dépôt donne un historique vérifiable de la progression réelle du compilateur Vitte.