Lire un programme Vitte
Les déclarations, les blocs et les signes de ponctuation forment l’ossature des programmes Vitte. Leur rôle permet de distinguer rapidement la structure d’un fichier de son comportement.
Le fichier est une suite de déclarations
À la différence d’un script où chaque ligne est nécessairement une instruction immédiate, un fichier Vitte contient surtout des déclarations : module, import, constante, forme, procédure, et ainsi de suite. Une déclaration donne un nom ou une structure que d’autres parties du programme peuvent utiliser.
space tutorials::syntaxe;
const REPONSE: i64 = 42;
proc lire_reponse() -> i64 {
return REPONSE;
}
proc main() -> i64 {
return lire_reponse() - REPONSE;
}
Dans cet exemple, le fichier déclare son module, une constante, puis une procédure. L’ordre permet au lecteur de découvrir d’abord le contexte et ensuite le comportement. Le compilateur analyse l’ensemble du fichier pour relier les noms à leurs déclarations.
Le fichier complet examples/tutorials/syntaxe.vit appelle la procédure et vérifie que la constante vaut 42.
build/bin/vitte run examples/tutorials/syntaxe.vit --quiet --no-colorRésultat confirmé : code de sortie 0.
La ponctuation a un rôle précis
- Les parenthèses
( )encadrent les paramètres d’une procédure ou les arguments d’un appel. - Les accolades
{ }délimitent un bloc, par exemple le corps d’une procédure ou d’une condition. - Les deux-points
:séparent souvent un nom de son type :REPONSE: i64. - La flèche
->introduit le type de retour d’une procédure. - Le point-virgule
;termine plusieurs déclarations et instructions. ::sépare des éléments dans un chemin de module ou un nom qualifié.
Un bloc peut contenir plusieurs instructions. L’indentation ne remplace pas les accolades : elle sert aux personnes qui lisent le code. Gardez une indentation régulière, car elle rend visibles les blocs imbriqués et les erreurs de fermeture.
Commentaires : écrire pour la prochaine lecture
Un commentaire explique une intention, une règle ou une subtilité qu’on ne peut pas déduire facilement du code. Vitte accepte les commentaires de ligne //, les commentaires de documentation /// et les commentaires de bloc /* ... */. Les commentaires de bloc peuvent être imbriqués dans la grammaire du dépôt.
// La limite est exclusive pour simplifier le parcours.
const LIMITE: i64 = 10;
/// Renvoie le double d'une valeur.
proc doubler(valeur: i64) -> i64 {
return valeur * 2;
}
Évitez de commenter chaque ligne pour la paraphraser. Une bonne explication répond plutôt à « pourquoi cette limite ? », « quelle hypothèse faisons-nous ? » ou « que doit garantir cette procédure ? ».
Noms, majuscules et littéraux
Les identifiants commencent par une lettre ou un souligné, puis peuvent contenir des chiffres et d’autres caractères autorisés. Les noms sont sensibles à la casse : score et Score sont deux noms différents. Le dépôt emploie souvent snake_case pour les procédures et variables, et des majuscules pour les constantes et les types.
Un littéral est une valeur écrite directement dans le code : 42, 3.5, true, 'v', "salut" ou null. Les entiers peuvent également être écrits en binaire (0b1010), en octal (0o12) ou en hexadécimal (0xA). Les caractères spéciaux dans une chaîne se notent avec une barre oblique inversée, par exemple \n pour un saut de ligne.
Lorsqu’un fichier paraît difficile à suivre, les déclarations du niveau supérieur donnent le premier repère. Les blocs imbriqués révèlent ensuite les limites de portée, puis les expressions montrent les calculs réalisés à l’intérieur de ces blocs.
Lecture détaillée d’un programme
Dans le programme de départ, la déclaration de module fournit le contexte du fichier ; la signature de main annonce son nom et son type de retour ; l’appel à print produit l’affichage ; l’instruction return termine la procédure. Si une accolade ou un point-virgule manque, la commande vitte parse permet d’observer à quelle étape le parseur détecte la structure incomplète.
Du texte aux structures : trois niveaux
Quand Vitte lit un fichier, le compilateur ne voit pas directement « une fonction qui calcule ». Il avance par niveaux. Le lexer identifie les tokens : mot-clé, identifiant, nombre, opérateur et ponctuation. Le parseur assemble ces tokens selon la grammaire pour reconnaître une déclaration, un bloc ou une expression. L’analyse sémantique relie ensuite des noms aux déclarations et vérifie des contraintes comme les types attendus.
Ces niveaux expliquent pourquoi des erreurs ressemblantes demandent des corrections différentes :
proc somme( -> i64 {a une structure incomplète : le parseur ne peut pas reconnaître la liste de paramètres.let resultat: i64 = nom_absent;peut avoir une syntaxe correcte, mais l’analyse sémantique doit encore résoudrenom_absent.let resultat: bool = 3;peut être bien formé, mais le type de la valeur doit correspondre au type annoncé.
Ces extraits montrent la nature des problèmes, pas une garantie que chaque voie de compilation émettra le même diagnostic. Examinez un seul problème à la fois avec lex, puis parse, puis check.
Construire l’arbre de lecture d’une déclaration
Dans proc lire_reponse() -> i64 { return REPONSE; }, le bloc appartient à la procédure, le retour appartient au bloc, et REPONSE est l’expression de retour. L’accolade fermante termine d’abord le corps, pas le fichier entier. Dans un fichier long, les déclarations du niveau supérieur constituent une carte de lecture avant l’examen détaillé des corps de procédure.
Le point-virgule termine ici l’instruction return. Il ne sert pas à séparer les arguments d’un appel, qui sont séparés par des virgules. Les accolades encadrent un bloc, tandis que les parenthèses encadrent les paramètres ou arguments. Lorsqu’un diagnostic signale une ponctuation manquante, la correction dépend de la structure active : une liste de paramètres attend une parenthèse, alors qu’un bloc attend une accolade.
Repérer les noms et la portée
Une constante déclarée au niveau d’un module, comme REPONSE, peut être référencée par une procédure selon les règles de visibilité et de résolution du compilateur. Un paramètre tel que valeur est disponible dans le corps de sa procédure. Une liaison locale est définie à l’intérieur d’un bloc et son usage dépend de la portée que le langage attribue à ce bloc.
Les noms sont sensibles à la casse : REPONSE, Reponse et reponse ne désignent pas le même identifiant. Si un nom n’est pas reconnu, comparez attentivement sa graphie, son module, son import et sa visibilité. Le fait qu’un mot ressemble à un nom de type ne le rend pas automatiquement disponible.
Pour return lire_reponse() - REPONSE;, le point d’entrée appelle d’abord lire_reponse, récupère sa valeur, puis soustrait la constante. Comme lire_reponse renvoie la même constante, le résultat attendu est zéro. Le fichier d’exemple vérifie ce comportement en se terminant avec le code 0.
La syntaxe forme une structure imbriquée
Les signes de ponctuation indiquent les relations entre les éléments. Dans proc lire_reponse() -> i64 { return REPONSE; }, les parenthèses délimitent les paramètres, la flèche relie la signature au type de retour, les accolades délimitent le corps et le point-virgule termine l’instruction. Cette structure est plus importante que le découpage visuel en lignes : un fichier pourrait être écrit sur une seule ligne et conserver les mêmes relations syntaxiques.
Le parseur construit une représentation hiérarchique. La déclaration de procédure contient une signature et un corps ; le corps contient une instruction de retour ; le retour contient une expression qui référence un nom. Lire le code comme un arbre évite de confondre la fin d’une instruction avec la fin d’un bloc. Cela explique également pourquoi une accolade manquante peut produire des diagnostics sur plusieurs lignes suivantes : le parseur ne sait plus où le bloc aurait dû se terminer.
Identifier la première structure incorrecte
Une erreur de syntaxe est souvent signalée après le caractère qui aurait permis au parseur de poursuivre, et non exactement à l’endroit où la cause a été introduite. Une parenthèse d’ouverture oubliée peut rendre suspecte la virgule suivante ; une accolade qui manque peut faire paraître invalide la déclaration qui suit. Le premier diagnostic est donc généralement le plus informatif. Les erreurs en cascade disparaissent souvent lorsqu’une seule frontière structurelle est rétablie.
Il faut distinguer une forme mal construite d’un nom inconnu. let resultat: i64 = nom_absent; peut respecter les règles de ponctuation tout en échouant à la résolution du nom. De la même manière, une déclaration structurée peut référencer un nom valide mais échouer plus tard sur une incompatibilité de type. Les commandes séparées permettent de situer le problème dans le pipeline au lieu de modifier la ponctuation au hasard.
Les commentaires et les noms font partie de l’interface humaine
Un commentaire de ligne // convient à une remarque locale ; /// associe une documentation à une déclaration ; /* ... */ encadre un commentaire de bloc. Les commentaires ne changent pas le résultat de l’analyse des expressions, mais ils font partie de la maintenance du programme. Une explication utile décrit une intention difficile à déduire — unité, invariant, convention ou raison d’une limite — plutôt que de répéter la ligne qui suit.
Les identifiants sont sensibles à la casse. Dans un diagnostic « nom inconnu », l’écart peut être une lettre majuscule, un chemin de module, un import absent ou une déclaration privée. Ces causes se situent à des niveaux distincts. La graphie du nom établit son identité ; le chemin établit où chercher ; l’import donne accès au module ; la visibilité détermine ce qui peut être référencé depuis l’extérieur.
Les séparateurs établissent les frontières
Le point-virgule termine certaines déclarations et instructions ; il ne ferme ni une procédure ni un module. La virgule sépare des éléments dans une liste, comme les paramètres ou les champs d’une forme. Les deux-points associent souvent un nom à une information de type. Les accolades ouvrante et fermante encadrent une région syntaxique complète. Lire ces signes comme des frontières évite de les traiter comme une décoration facultative.
Dans un bloc imbriqué, chaque accolade fermante correspond à une ouverture précise. L’indentation sert à aligner visuellement ces régions, mais elle ne remplace pas la structure que le parseur lit. Une indentation cohérente permet de repérer plus vite une accolade isolée ; la correction finale dépend néanmoins de la grammaire et des diagnostics de parsing.
La graphie d’un chemin n’est pas un identifiant isolé
Dans space tutorials::syntaxe;, le chemin contient plusieurs segments reliés par ::. Chaque segment participe à l’identité logique du module. Le même séparateur peut apparaître dans un appel qualifié, par exemple calcul::additionner, où il exprime une relation entre un alias de module et une déclaration. Le contexte permet au parseur de savoir si la séquence appartient à une déclaration, un import ou une expression.
Les sources du dépôt montrent aussi des séparateurs de type barre oblique dans certaines déclarations. Les formes acceptées sont décrites dans la grammaire, mais la résolution réelle dépend des règles du frontend et de la configuration de recherche. La ponctuation reconnue ne dit pas, à elle seule, si le chemin désigne un fichier existant ou un nom public.