Sémantique de XL1
Le niveau XL1 est défini comme une une séquence d'opérations sur l'arbre syntaxique du niveau XL0. Ces opérations sont effectuées par divers plugins du compilateur qui sont appelés suivant la forme de l'arbre syntaxique.
Des constructions particulières, translate et translation, sont fournies par un plugin destiné à faciliter l'écriture d'autres plugins. La construction quote génère un arbre syntaxique. Voici comment ces constructions peuvent être utilisées pour implémenter un plugin nommé ZeroRemoval, qui supprime les aditions et multiplications par zéro :
translation ZeroRemoval when 'X' + 0 then return X when 'X' * 0 then return parse_tree(0)
Un plugin peut être invoqué sur un fichier complet à partir de la ligne de commande, ou plus localement dans le source du code en utilisant la notation pragma, comme ici :
X := {Differentiate} d(sin(omega * T) * exp(-T/T0)) / dT
Le niveau XL1 contient un grand ensemble de plugins, notamment XLSemantics qui donne les abstractions communes telles que fonction, type de données et déclaration de variable et définition, et aussi les ordres de base de la programmation structurée que sont les boucles et les conditions.
Système de typage
XL1 contrôle le type statique, avec des possibilités de programmation générique qui vont au-delà de celles de C ou Ada. Les types comme les tableaux ou les pointeurs, qui sont des types primitifs en C, sont déclarés dans une bibliothèque dans XL. Par exemple, le type d'un tableau d'une dimension peut être définit par :
generic [Item : type; Size : integer] type array
Un type générique validé est un type générique où une condition indique comment le type peut être utilisé. De tels types ne doivent pas avoir de paramètres génériques. Par exemple, on peut déclarer un type comme ordered (ordonné) si un opérateur inférieur est présent :
// Un type est ordonné en présence d'un opérateur inférieur generic type ordered if A, B : ordered Test : boolean := A < B
Il est alors possible de déclarer une fonction qui est implicitement générique puisque le type ordered est lui-même ordonné.
// Function générique pour au moins un élément function Min(X : ordered) return ordered is return X
Ceci s'applique aussi aux types génériques qui ont des paramètres, comme array. Une fonction calculant la somme des éléments dans un tableau peut s'écrire :
function Sum(A : array) return array.Item is for I in 0..array.Size-1 loop result += A[I]
Type protégé de liste de variable d'arguments
Les fonctions peuvent être surchargées. Une fonction peut être déclarée avec un nombre variable d'arguments grâce au mot other dans la liste des paramètres. Dans une telle fonction, other permet de passer un nombre variable d'arguments à une autre fonction :
// Fonction générique pour le minimum de N éléments function Min(X : ordered; ...) return ordered is result := Min(...) if X < result then result := X
Quand ce genre de fonction est appelée, le compilateur invoque les fonctions de manière récursive pour correspondre à la liste :
// Exemple d'utilisation de la fonction Min précedente X : real := Min(1.3, 2.56, 7.21) Y : integer := Min(1, 3, 6, 7, 1, 2)
Réduction d'expression (surcharge d'opérateur)
Les opérateurs peuvent être définis en utilisant la forme written de déclaration de fonction. Voici un code qui déclare l'addition d'entiers :
function Add(X, Y: integer) return integer written X+Y
De telles formes écrites peuvent avoir plus de deux paramètres . Par exemple, une transformation de matrice linéaire peut s'écrire :
function Linear(A, B, C : matrix) return matrix written A+B*C
Une forme écrite peut utiliser des constantes, et ce type de forme est plus spécialisée que sans constantes. Par exemple :
function Equal(A, B : matrix) return boolean written A=B function IsNull(A : matrix) return boolean written A=0 function IsUnity(A : matrix) return boolean written A=1
Ce mécanisme est utilisé pour décrire tous les opérateurs de base. Une expression est progressivement réduite à des appels utilisant des formes écrites. Pour cette raison, ce mécanisme est appelé réduction d'expression plutôt que surcharge d'opérateur.
Itérateurs
Les itérateurs de XL permettent de programmer à la fois des générateurs et des itérateurs.
import IO = XL.UI.CONSOLE iterator IntegerIterator (var out Counter : integer; Low, High : integer) written Counter in Low..High is Counter := Low while Counter <= High loop yield Counter += 1 // I doit être déclaré, car indiqué comme 'var out' dans l'itérateur // Une déclaration implicite de I comme entier est alors faite ici for I in 1..5 loop IO.WriteLn "I=", I