URL: https://linuxfr.org/users/piervit/journaux/gufo-un-langage-de-shell-moderne Title: Gufo: un langage de shell moderne! Authors: Piervit Date: 2017年12月07日T10:24:06+01:00 License: CC By-SA Tags: fonctionnel, bash, shell, ligne, commande, linux et langage Score: 27 Gufo est un prototype de langage de script moderne qui peut embarquer des commandes unix et servir de shell. Pourquoi ======== Bash est, pour les utilisateurs techniques, l'interface texte majeure sous les systèmes GNU-linux. La raison principale est la facilité à appeler des programmes externes et la possibilité de combiner des flux d'entrées/sorties dans l'environnement orienté fichier de GNU-linux. En gardant conscience de la qualité et de la quantité de travail qui a été mise dans Bash, un système d'exploitation moderne mérite un langage de shell utilisant les techniques de compilation et d'interprétation modernes. En dehors de la simple exécution d'une ligne de commande, il est nécessaire de disposer d'un langage de shell permettant d'exécuter des scripts pouvant manipuler facilement des lignes de commandes (par exemple "nb_files=`ls -l | wc -l`"). Bash le permet mais d'une manière tout à fait archaïque. Modestement, mais avec une certaine envie de voir ce genre d'évolution, j'ai commencé à imaginer un nouveau langage pour le shell. J'ai travaillé à cette idée à temps partiel depuis septembre 2017 (l'idée, je l'avais depuis plus longtemps). Le projet est loin d'être déjà utilisable mais peut être considéré comme une "preuve de concept" (proof of concept) permettant d'annoncer les idées principales qui seront utilisées et d'obtenir des retours. Je considère les fonctionnalités suivante comme étant importante dans un langage 'moderne': * Un système de typage avancé: + la possibilité d'utiliser des tuples, listes, map et set (ensemble) en plus des types de bases. + une des innovations de Gufo est de considérer une commande shell comme un type de base. + la possibilité de créer ses propres types "struct". + le typage est "statique implicite": le programmeur ne déclare pas les types, ceux-ci sont inférés par l'interpréteur. * Un travail important de vérification pré-exécution: + Gufo est un langage interprété (bien logiquement pour un langage de shell) mais il fait des vérification sur le code avant de lancer l'exécution effective: l'idée est que l'on veut éviter autant que possible les échecs durant les exécutions (parce que l'utilisateur risque de perdre du temps si l'exécution du script est longue, ou pire risque de mettre le système dans un état inconsistant). C'est pourquoi, Gufo vérifie en amont de l'exécution que chaque variable est bien défini (à l'intérieur d'un scope), que les appels de fonctions sont consistent et fait une vérification de typage (type-checking). Dans l'état actuel de Gufo, beaucoup reste à faire, entre autre, il reste des questions sur l'utilisation des entrées/sorties (comment paramétrer leur affichage entre sortie standard et/ou stockage dans une variable), messages d'erreur correct mais sans aucune information de position dans le code, travail à faire pour rendre l'usage console agréable... L'objectif à terme est de fournir une version libre, mais je ne ferais cela que si le projet est suffisamment avancé au moins pour une utilisation basique ce qui n'est pas le cas aujourd hui. Cela dépend aussi des opportunités de financement du projet. Une description utilisateur =========================== Le meilleur moyen de gouter à Gufo, est de plonger dans quelques exemples compréhensibles aussi bien pour des débutants que pour des utilistateurs avancés. ## Une simple commande __code__ ls __explication__ Une simple commande shell est un programme Gufo valide, c'est ce qui lui permettra d'être un language de shell. La commande ls permet de lister les fichiers du répertoire courant. Ce programme permettra donc l'affichage de cette liste. ## Une commande avec redirection __code__ ls -l | wc -l> nb_files.txt __explication__ Gufo gère les opérateurs de redirections du bash. Pour information, "|" redirige la sortie de la première commande ("ls -l") vers la deuxième commande ("wc -l"). ">" redirige la sortie du résultat vers le fichiers nb_files.txt. La encore, le but est d'imiter bash, tout en reconnaissant qu'on ne le fait que pour les opérateurs simples, sans aller dans les fonctionnalités avancées (et souvent occultes). Gufo permet aussi à l'utilisateur d'interagir avec l'entrée standard dans le cas de programme interactif. ## Stockage d'une commande dans une variable __code__ let $a = ls -l | wc -l __explication__ Une variable en Gufo est toujours préfixé par un '\$' pour qu'il n'y ai pas ambigüité avec une commande. 'let' est le mot clé permettant de déclarer une variable ou une fonction. Le résultat de la commande (les système unix renvoit 0 pour une exécution réussi ou un entier non-nul indiquant l'erreur) est atteignable via "\$a.Cmd.res", le contenu du résultat via "\$a.Cmd.print_std". ## Une fonction basique __code__ let $factoriel $c = if ($c != 1) then $c * ($factoriel ($c - 1)) else 1 __explication__ Voici la fonction factoriel (qui ne dépend pas d'éventuelles lignes de commandes). Cette fonction prend un argument "\$c", si celui-ci est différent de 0, la fonction s'appelle récursivement (avec \$c décrémenté à chaque appel). La syntaxe, et de nombreux aspect du langage sont empruntés à Ocaml. Gufo est un langage fonctionnel (généralement pas d'effet de bord, une fonction prend des arguments et renvoi une valeur résultante). ## Une fonction avancé __code__ let $run $fichier = let $current_log = $fichier+".log" in( let $past_log = $fichier+".log.old" in( # put current log as past past log let $as_log = cat $current_log> $past_log in ( if $as_log.Cmd.res == (some 0) then (./gufo_run.native $fichier> $current_log; diff -q $current_log $past_log) else (echo "create first log"; ./gufo_run.native $fichier> $current_log) ))) __explication__ Voici d'abord une explication générale: le but de cette fonction est d'exécuter le programme externe "./gufo_run.native" prenant en paramètre une chaine de caractères (contenu dans '\$fichier') et de stocker son résultat dans le fichier référé par '\$current_log'. dans le cas ou la commande à déjà été exécuté on veut afficher le diff par rapport au log de l'exécution précédente. Voila le détails par ligne: 1. déclaration de la fonction '\$run' qui prend 1 argument '\$fichier'. Les lignes suivantes représente le corps de la fonction. 2. déclaration de la variable '\$current_log' qui correspond à la concaténation de '\$fichier' avec la chaine ".old". Le "in" indique la porté, délimiter par la paire de parenthèses, dans laquelle est utilisable la variable. 3. similaire à la ligne précédente, pour définir un "log.old". 4. un commentaire (commence toujours par # et se termine en fin de ligne). 5. exécution de la commande 'cat \$current_log> \$past_log', le résultat est mis dans la variable '\$as_log'. 6. un if et sa condition: la condition est vrai si le résultat de la commande vaut 0 (le "some" sera détaillé mais permet de différencier un cas ou l'exécution de la commande s'est effectivement produit, d'un cas ou celle-ci ne ce serait pas produit (on aurait un "none). 7. l'exécution dans le cas ou la condition est vérifié: exécute le programme "gufo_run.native avec comme argument '\$fichier' en mettant le résultat dans le fichier indiqué par '\$current_log' On exécute successivement la commande diff. 8. l'exécution dans le cas ou la condition n'est pas vérifiée: exécution d'une commande "echo" suivi de l'execution de la commande "./gufo_run.native". 9. fermeture des portés de variables ouvertes. ## Divers Il y aurait de nombreuses autres fonctionnalités à montrer, elles seront présentés dans un tutoriel plus complet (en particulier, concernant les tuples, listes, set et map...). Voila simplement un dernier exemple pour expliquer qu'il y a un système de type "personnalisé", semblable au struct du C: __code__ struct $mystruct= { var1: string , var2: cmd, var3: $myotherstruct, var4: string -> int, } __explication__ On a défini un type '\$mystruct' disposant de quatre champs nommés et respectivement typés. Le champs "var3" a pour type une autre structure, le champs "var4" à pour type une fonction prenant une chaine de caractère et retournant un entier. Une description technique ========================= La description ici faîtes n'est que très partielle et est voué à être détaillé à l'avenir. Gufo est codé en Ocaml et fait environs 5000 lignes. Il repose beaucoup sur les mécanismes d'ocaml (type (le int de Gufo est strictement le int d'ocaml, gestion de la mémoire...) mais ajoute le mécanisme de commande externe, de set et map sans passer par des foncteurs et rend plus facile (d'avantage "script") son utilisation. Il ne cherche pas atteindre ces mécanismes avancés. Le code est parsé puis est transformé dans une représentation intermédiaire optimisée (tous les symboles sont remplacés par des entiers ce qui permet des gains importants de performances). Gufo est un language fonctionnel et si il permettra quelques astuces impérative, le restera. ![Image of the core](http://pvittet.com/schema.png) L'état du projet ================ Mon objectif était d'avancer au maximum le projet avant de le présenter pour pouvoir donner autant de précision et de garantie que possible sur les qualité du langage. Le projet tout de même apparaît bien ambitieux et je ne peux pas d'avantage le développer sans soutien financier. J'ai donc décidé de faire cette présentation, pour présenter honnêtement le projet, vous permettre de l'évaluer et de considérer si il vous paraissais utile de l'aider. Votre avis me sera utile pour savoir si le projet semble avoir du sens. Votre aide, cela peut être des remarques, des conseils, et également des perspectives de financement si le projet vous semble pertinent. Selon les réactions, j'organiserais une campagne de financement. Je tiens à préciser que quoi qu'il arrive, le logiciel est destiné, si il est publié à être publié sous licence libre. Pour autant, je considère que tout travail (utile) mérite salaire: la qualité de la publication dépendra de l'aide reçu. Pour l'instant, je souhaite en être le seul développeur, jusqu'à cette première publication éventuelle. Ensuite, nous verrons la situation, mais comme indiqué, le projet sera libre. Voici les nombreux points qui devraient être travaillés pour envisager une version "aboutie": * Finalisation du type-checker (déjà relativement avancé) * Amélioration de la gestion des commandes (en particulier sur le type permettant de stocker l'exécution d'une commande: que veux t'on stocker?) * amélioration des levés d'erreurs, en particulier position de l'erreur dans le code (je considère cela tout à fait essentiel mais ai laissé cette fonctionnalité pour plus tard car elle n'était pas nécessaire pour estimer la faisabilité pure.) * Gestion et écriture des modules systèmes (List, Set, Map, Cmd....) fournissant un ensemble de fonctions standards. * Documentation complète * Mise en place d'outils de programmation impératives: séquence d'expressions, pointeurs sur des valeurs mutables... * Validations et écriture de programmes de test conséquents * possibilité qu'une structure étende une autre structure (pourrait ressembler à des mécanismes de programmation objet). * Pour les questions de gestions de la mémoire, je me repose sur Ocaml, langage dans lequel est codé Gufo. Si vous êtes curieux vous pouvez me contacter: [http://pvittet.com/?page=contact](http://pvittet.com/?page=contact). Pour conclure, j'ai eu, en tant qu'ingénieur en informatique, plusieurs fois l'opportunité de travailler avec des chercheurs, Je n'aurais certainement pas eu l'imagination ni les moyens de me lancer dans un tel projet sans ces expériences. Aussi, je tiens à leur exprimer mes remerciements.

AltStyle によって変換されたページ (->オリジナル) /