
Swift n'est pas seulement un langage de programmation. Il s'agit d'un projet qui, en plus du compilateur, comprend de nombreux autres composants. Et le compilateur lui-même n'est pas une grosse et terrible boîte, qui à l'aide de la magie transforme votre code en un ensemble d'instructions compréhensibles pour la machine. Il peut également être décomposé en composants. Si vous êtes intéressé par lesquels, bienvenue à cat.
Je ne suis pas un spécialiste des compilateurs et je n'ai aucune expérience dans ce domaine. Mais je me suis demandé comment cela fonctionnait et j'ai commencé à étudier le compilateur Swift. Comme l'article s'est avéré trop volumineux, j'ai dû le diviser en 4 parties:
- aperçu général des composants
- analyser le fichier source,
- Langage intermédiaire rapide,
- LLVM IR et génération de code.
Rapide
Swift est un projet open source depuis plus de deux ans maintenant. Pendant ce temps, de nombreuses améliorations de la communauté y ont été ajoutées. Vous pouvez les suivre sur un site spécial, ainsi que sur le forum . Là, vous pouvez discuter de suggestions pour améliorer la langue ou exposer vos idées. Mais pour ce faire, vous devez d'abord comprendre comment fonctionne le projet.
Bibliothèque standard Swift

Les parties principales de Swift, bien sûr, sont le compilateur et la bibliothèque de fonctions standard. Ils se développent en parallèle et sont pratiquement indissociables les uns des autres.
Le compilateur est écrit en C ++, et la partie principale de stdlib est en Swift. Cependant, le langage utilisé contient plusieurs fonctionnalités:
- La bibliothèque standard via le module Builtin a un accès direct aux fonctions du compilateur. Cela lui permet d'accéder à des représentations de langage de bas niveau et à des pointeurs bruts.
- La bibliothèque standard n'utilise pas le modificateur d'accès privé. Au lieu de cela, les noms d'entités non publiques commencent par un trait de soulignement. Lisez plus ici .
- Il utilise la génération de code à l'aide de l' utilitaire Generate Your Boilerplate (GYB) pour réduire la répétition dans le code de la bibliothèque standard.
La bibliothèque standard est généralement associée à des conteneurs et à des fonctions utiles qui simplifient la vie du développeur, mais ce n'est qu'une partie. Au total, 3 composants les plus intéressants peuvent être distingués:
- Noyau Un noyau avec tous ses protocoles, types de données et fonctions. Sources .
- Runtime Une couche intermédiaire entre la bibliothèque standard et le compilateur. Il est responsable de la fonte de caractères, du travail avec la mémoire, la réflexion et d'autres caractéristiques dynamiques du langage. Écrit en C ++ et Objective-C. Sources .
- Superpositions du SDK. Wrappers sur Foundation et d'autres frameworks système qui rendent l'accès à Swift plus pratique. Sources .
Autres sous-projets

En plus du compilateur et de la bibliothèque standard, il existe de nombreux autres sous-projets dans le domaine public. Certains d'entre eux sont énumérés ci-dessous.
Sourcekit
Framework de support IDE : indexation, coloration syntaxique, complétion de code, etc.
SourceKit-LSP
Une implémentation de LSP pour Swift , basée sur SourceKit. Vous pouvez lire ce que c'est ici .
Gestionnaire de paquets Swift
Gestionnaire de packages pour les projets sur Swift.
Fondation
Port de la bibliothèque de la Fondation , qui est l'un des noyaux du système d'exploitation d'Apple pour les plates-formes tierces.
libdispatch (gcd)
GCD pour les plateformes tierces.
XCTest
XCTest pour les plateformes tierces.
LLDB
LLDB avec prise en charge Swift et REPL.
Support pour aire de jeux
Le projet comprend deux cadres - PlaygroundSupport et PlaygroundLogger. Ils fournissent une interaction avec Xcode et un bel affichage des données, respectivement.
llbuild
Construisez le système .
gyb
Utilitaire pour la génération de code.
libcxx
Implémentation de la bibliothèque C ++ standard.
Compilateur Swift

Un compilateur au sens large est un programme qui convertit le code d'une langue à une autre. Mais le plus souvent, la compilation fait référence à la conversion du code source en code machine (ou en une autre représentation de bas niveau), qui peut ensuite être utilisée pour créer un fichier exécutable.
Le compilateur est souvent divisé en trois parties: frontend, middlend, backend. Le premier est responsable de la conversion du code source en une représentation intermédiaire, ce qui est pratique pour le compilateur. Middlend effectue l'optimisation et le backend génère du code machine à partir de la représentation intermédiaire optimisée.
Cependant, dans Swift, l'optimisation est effectuée à la fois dans le frontend et (la plupart) dans le backend. Par conséquent, l'étape intermédiaire dans le diagramme n'est pas représentée.
LLVM

Le compilateur Swift utilise LLVM comme backend. LLVM est un grand projet qui comprend de nombreuses technologies. Il est basé sur une représentation intermédiaire (IR). Il s'agit d'une représentation de code intermédiaire universel qui peut être convertie en code exécutable sur n'importe quelle plate-forme prise en charge par LLVM.
Si une nouvelle architecture apparaît, il suffira d'ajouter dans LLVM la génération de code machine à partir d'IR pour cette plateforme. Après cela, tous les langages pour lesquels il existe un compilateur avec génération IR prendront en charge cette architecture.
En revanche, pour créer un compilateur pour un nouveau langage de programmation, il suffit d'écrire la traduction du code source en IR, et LLVM se chargera des différentes architectures.
Un autre avantage d'un tel système est que LLVM peut optimiser la présentation intermédiaire, et le frontal peut ne pas être engagé dans l'optimisation. Cela simplifie considérablement le développement du compilateur.
IR a trois types d'affichage:
- Un arbre d'objets en mémoire. Chaque objet correspond à une certaine entité dans le code source: fonction, opérateur, ligne, pointeur, etc. Cet arbre est créé par l'interface au stade de la génération IR.
- Vue texte. IR peut être déduit en tant que code source de bas niveau. Il peut être enregistré dans un fichier et exécuté à l'aide de l'interpréteur.
- Le format binaire sérialisé «bitcode» (à ne pas confondre avec le bytecode, qui est utilisé, par exemple, en Java). Il peut être utilisé comme résultat final du backend et transféré à l'éditeur de liens pour une optimisation au niveau du lien. La conversion en code machine dans ce cas sera effectuée par l'éditeur de liens.
Linker est un programme qui génère un fichier exécutable. Sa description dépasse le cadre de l'article.
Le code source de la version LLVM utilisée dans Swift peut être trouvé ici , et la documentation sur le site officiel .
Comme vous pouvez le voir, Apple a publié de nombreux projets intéressants en libre accès. Dans la partie suivante, je parlerai de l'analyse du fichier source et de la génération de l'AST.