Compilation Vers Java Script

Les scripts Qubes disposent d'un compilateurs vers JavaScript introduit avec la version Qubes 2016.

Lors d'une compilation vers JavaScript, le code sera "transpilé" en JavaScript, en s'efforçant par défaut de conserver la structure du code, le nom des classes, fonctions et variables. Ceci permet de déverminer directement le JavaScript généré.

  • Les fonctionnalités avancées non supportées nativement en JavaScript (typage fort, héritage, surcharge, méta-classes, types valeurs, helper, interfaces...) sont gérées au travers d'une génération de code spécifique.
  • La dynamicité des objets génériques est supportées au travers du type Variant, pour lequel le typage et les méthodes sont purement traités à l'exécution. Cependant cela interdit les vérifications de types à la compilation.
  • Les classes (et record) anonymes peuvent être utilisés pour la création en ligne d'objet JavaScript.
  • La capture (closure) est supportée, ainsi que les fonctions lambda.
  • La déclaration de structure et fonctions JavaScript avec un typage fort est possible avec les classes et méthodes externes.

1. Interface avec les structures natives JavaScript

Le language permet d'exposer au script des structures natives du JS et vice-versa.

1.1 Variant

Le type variant est équivalent à un objet standard du JS, ie. non typé, avec des méthodes, des index et une existence contrôlée uniquement à l'exécution. Quand le type Variant est utilisé, le compilateur n'effectue qu'une vérification syntaxique simple, et ne vérifiera ni les noms ni le type ou le nombre des paramètres.

function Test(v : Variant) : Variant;
begin
   exit v.Call(1, 2);
end;

sera compilé en

function Test(v) {
   return v.Call(1, 2);
}

sans aucun contrôle sur l'existence d'une méthode Call, de son nombre de paramètres ni de leur types. Toute erreur ne sera détectée qu'à l'exécution.

1.2 Fonction externes

Exposent une fonction (ou une pseudo-fonction) du JS, qui sera alors vérifiée syntaxiquement et grammaticalement par le compilateur (et proposé à l'autocompletion), par exmple

function EncodeURI(s : String) : String; external 'encodeURI';

Le nom externe est substitué "tel quel" lors de la composition, il est possible de référencer des methods d'une instance globale

function ElementByID(id : String) : JElement; external 'document.getElementById';

Enfin une fonction externe qualifiée comme "property" permet d'exposer les pseudo-variables globales du JS qui ne doivent être accédées qu'en lecture

function Math : Variant; external 'Math' property;

1.3 Classes externes

Les classes externes exposent des classes JS en permettant une vérification syntaxique et grammaticale par le compilateur.

Par exemple le code ci-dessous est une déclaration partielle de la classe JS "Date" qui sera exposée comme "JDate" en script. La convetion de préfixe "J" est utilisé pour dénoter visuellement les classes JavaScript et les distinguer des classes de script.

type
   JDate = class external 'Date'

      constructor Create(); overload; external;
      constructor Create(millisecondsSinceEpoch : Float); overload; external;

      function GetSeconds : Integer; external 'getSeconds';
      function GetMinutes : Integer; external 'getMinutes';
      function GetHours : Integer; external 'getHours';
   end;

La declaration expose deux constructeurs, avec ou sans paramètre, ainsi que 3 méthodes. Les méthodes sont déclarées en script en Pascalcase et "external" est utilisé pour spécifier leur nom en JS (qui est en camelCase).

La classe ci-dessus peut alors être utilisée en script avec un typage fort:

var d := new JDate; // d sera de type JDate
var h := d.GetHours; // h sera de type Integer
PrintLn(h);

qui serait compilé en JS comme

var d = new Date(); // d est non typée
var h = d.getHours(); // h est non typée
document.writeln(h);

1.4 Sections asm

Il est possible d'utiliser une section (comme assembleur) pour inclure du code JavaScript bas niveau. Dans ces sections l'opérateur @ peut être utilisé pour référencer un variable ou une entité définie en script, afin qu'elle soit correctement générée en cas de déduplication ou d'obfuscation.

Au sein des section asm le compilateur n'effectuer plus aucune vérification syntaxique, ce qui permet d'utiliser des aspects ésotériques du JS. Les cas d'usages sont néanmoins limités.