Journal Valisp, un langage (pseudo-)Lisp au-dessus de Vala

Posté par (page perso) . Licence CC by-sa
48
15
oct.
2013

Sommaire

Cher journal, je me permets de te présenter un projet personnel à l'intérêt assez limité : le langage jouet Valisp, qui a pour objectif d'ajouter une couche « Lispienne » au langage Vala.

Mais pourquoi ?

Parce que ! Vala tout seul, ce n'est pas assez rigolo : c'est juste un langage (Vala) qu'il faut compiler dans un autre langage (C) qu'il faut ensuite compiler à nouveau, ce qui est beaucoup trop direct, admettons-le.

We need to go deeper

Valisp est donc un langage qu'il faut compiler dans un autre langage qu'il faut compiler dans un autre langage qu'il faut compiler à nouveau. Et en plus, comme c'est inspiré du Lisp, il y a plein de parenthèses.

Ça ressemble à quoi ?

À du Lisp (c'est le but), mais avec quelques informations de types en plus (parce que Vala est typé statiquement et que le but est de pouvoir utiliser Vala directement). Un petit exemple de code qui utilise la bibliothèque Gtk+ (c'est l'adaptation du premier programme de la page des exemples d'utilisation de Gtk+ en Vala :

(defn main int [args <string>]
  (Gtk.init (ref args))
  (let [[win (new Gtk.Window)]
        [button (new Gtk.Button.with_label "Plop!")]]
        (win.destroy.connect Gtk.main_quit)
        (set! win.title "42")
        (button.clicked.connect 
         (fn void []
           (set! button.label "Coin!")))
        (win.add button)
        (win.show_all)
        (Gtk.main)
        0))

(Une fois compilé (et re-compilé avec valac), ça affiche une fenêtre avec un bouton « Plop! » qui devient « Coin! » quand on clique dessus.) 

Donc voilà, il n'y a rien de très original si vous avez déjà utilisé des dialectes de Lisp, mis à part le int et le <string> dans la définition de la fonction main, le premier spécifiant un type de retour int et le second un paramètre de type tableau de string.

C'est fait comment ?

Comme la syntaxe est proche du Lisp, le plus simple était d'écrire le compilateur dans un langage de ce type, puisque grâce à l'homoiconicité (j'espère que j'utilise bien le bon terme) c'est trivial de prendre un fichier source et d'obtenir une structure de données correspondant au code. Comme j'aime bien Clojure j'ai donc utilisé ce langage (et parce que comme c'est compilé sur la JVM et qu'il faut charger toutes les classes de Clojure avant que le programme s'exécute, ça met quelques secondes et ça fait croire que le compilateur fait des choses intelligentes et compliquées alors qu'en fait pas du tout).

Ça s'utilise comment ?

Il y a deux possibilités : soit installer Leiningen, cloner le repository git et faire

$ lein run

dans le bon répertoire ; ou alors, plus simple, récupérer le Jar de la version 0.1 et le lancer avec :

$ java -jar valisp-0.1-standalone.jar

Dans tous les cas, ce sera plus utile si vous passez en paramètre un fichier qui contient du code Valisp. Il y a quelques exemples de programmes qui devraient compiler sur Github.

Ça fait quoi, en vrai ?

Bon, en vrai c'est super pompeux d'appeler ça un compilateur. Déjà, tout ce qui concerne la transformation du code Valisp en Abstract Syntax Tree, c'est Clojure qui le fait grâce à un appel à read, donc c'est vite fait. Il n'y a donc que l'aspect « génération de code » que j'ai écrite. En plus, je suis tellement une feignasse qu'il n'y a aucune réelle vérification que le code produit est correct (après tout, il y a déjà le compilateur Vala pour ça, j'allais pas m'embêter (et en plus, comme le but c'est de pouvoir utiliser directement les fonctions et objets qui existent dans Vala, ça aurait nécessité un boulot assez compliqué, notamment de d'abord parser les
API Vala)). Le tout est sans doute codé de façon assez gruikesque, mais ça marchouille avec quelques exemples.

Sinon, il y a un certain nombre de choses qui sont implémentées, comme la définition de fonctions nommées, de closures, les définitions de variable, les boucles, etc (la liste des fonctionnalités implémentées est ici). Il y a aussi des choses qui ne le sont pas : pas de possibilité de définir de nouvelle classe, par exemple, ni de définir une fonction template.

Et ça a un intérêt ?

Honnêtement, non, le but c'était surtout de m'amuser un peu avec Clojure. Après, dans l'absolu, on aime ou on n'aime pas la syntaxe Lisp, mais je trouve élégante l'uniformité de ce langage, au lieu d'avoir souvent des structures assez différentes pour faire la même chose dans des contextes différent. Deux exemples pour Vala (et pas mal d'autres langages) :

  • la définition de fonctions et de closures qui ont une syntaxe assez différentes (int nom (int x) {return 42 * x;} VS (x) => {return 42 * x} ;
  • la différence pour la condition selon qu'on veuille pouvoir utiliser la valeur comme résultat ou pas (if (condition) {expr1} else {expr2} VS condition?expr1:expr2.

Cela dit, pour faire des applications GNOME en Lisp, je recommande plutôt d'utiliser Clojure avec les bindings java-gnome, ou d'autres bindings pour d'autres Lisp.

Et après ?

Le but étant surtout de faire un langage jouet, et le projet étant assez inutile tout de même, je ne pense pas mettre énormément d'énergie pour développer ce projet — il y a déjà suffisamment de langages obscurs comme ça. Éventuellement, si j'ai la motivation, j'essaierais bien de porter le « compilateur » Valisp en Valisp, parce que ce serait cool, ce qui implique quand même un peu de boulot (notamment de créer (ou de voir si ça existe dans les libs Vala) une structure de données pour stocker les listes façon Lisp).

Le mot de la fin ?

Valisp ça sert à rien, mais Clojure c'est cool (même si c'est lent au démarrage).

  • # Bon courage pour écrire le débugger!

    Posté par . Évalué à 5.

    ;-)

  • # Commentaire supprimé

    Posté par . Évalué à 7.

    Ce commentaire a été supprimé par l'équipe de modération.

    • [^] # Re: Macro ?

      Posté par (page perso) . Évalué à 7.

      J'ai loupé quelque chose ? Ou c'est plutôt un langage statique avec une syntaxe à la lisp ?

      Oui t'as raison, j'ai peut-être pas assez insisté là-dessus, c'est pour ça que j'avais mis «Pseudo-lisp», mais ça aurait sans doute été plus honnête de parler uniquement de syntaxe préfixée, en fait.

      Effectivement un vrai compilateur Lisp ça demanderait beaucoup plus de boulot (et de compétences) et une méthode moins naïve et à l'arrache :)

  • # Livre sur les compilateurs

    Posté par (page perso) . Évalué à 5.

    À propos des compilateurs, j'ai presque fini de lire Engineering a compiler, de Cooper et Torczon (de l'université de Rice). Je n'ai pas regretté mon achat, c'est bien expliqué, on a une bonne vue d'ensemble de ce que fait un compilateur, et les différents moyens d'implémentation pour chaque phase. Il faut évidemment avoir de bonnes notions d'algorithmique pour comprendre un livre sur les compilos.

    C'est là qu'on se rend compte qu'un compilateur comme GCC est un véritable monstre, qu'il y a plein d'algos compliqués, et que ça doit pas être évident d'arriver à un tel résultat (toutes les optimisations possibles, le nombre d'architectures supportées, …).

    « Un animal d'une atterrante stupidité : il est persuadé que si vous ne le voyez pas, il ne vous voit pas non plus » (H2G2)

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.