L'interpréteur en ligne de commande (yes.exe)

yes.exe est l'interpréteur YScript autonome — un exécutable qu'on lance directement depuis un terminal, sans écrire de code C#. C'est l'équivalent du lua.exe/« standalone interpreter » du manuel Lua. Cette page s'adresse à quelqu'un qui exécute des scripts YScript en ligne de commande ; pour embarquer le moteur dans une application .NET, voir Moteur.

yes.exe monscript.yes arg1 arg2
yes.exe -i
yes.exe -e "print(1+1)"

yes.exe construit un ScriptEngine sur un hôte console (ConsoleHost) et ouvre toutes les bibliothèques standard, sans exception : OpenLibs() (base, coroutine, package, table, math, string, regex, debug), plus OpenIOLib() (io.*), OpenOSLib() (os.*) et OpenDotnetLib() (dotnet.*, interop .NET complète). Contrairement à un hôte embarqué, qui choisit d'ouvrir un sous-ensemble précis selon ses besoins (voir Démarrage), l'interpréteur standalone n'a pas de raison de restreindre quoi que ce soit : un script lancé depuis la ligne de commande a par construction accès au système de fichiers, à l'horloge/au process et à la réflexion .NET du process qui l'exécute.

Syntaxe d'invocation

yes.exe [options] [script [args]]

Options

Option Effet
-e stat Exécute la chaîne stat comme un chunk de code YScript.
-l name Équivalent à name = require("name") : charge la bibliothèque/le module name et l'assigne à la variable globale du même nom.
-i, --interactive Passe en mode interactif (REPL) une fois le script (et les -e/-l) exécuté(s).
-p file, --profile file Charge file comme fichier de profil au lieu du profil par défaut. file doit exister.
--no-profile Désactive le chargement d'un profil, par défaut ou explicite.
-c, --command Force la résolution de script comme commande d'un paquet plutôt que comme fichier littéral (voir plus bas).
-v, --version Affiche l'en-tête (version du moteur, copyright) avant de continuer — n'arrête pas l'exécution.
-d, -D, --debug Active l'affichage d'informations de déboguage (y compris dans le REPL).

Les options courtes se combinent (-vi = -v -i) sauf -e, -l et -p, qui consomment le reste de leur propre argument (-emonstat) ou, s'il n'en reste pas, l'argument suivant sur la ligne de commande (-e monstat) — placez-les en dernier dans un groupe combiné, ou seules. -e et -l peuvent apparaître plusieurs fois ; ils sont alors exécutés dans l'ordre où ils apparaissent sur la ligne de commande.

Une option longue inconnue (--truc), une option courte inconnue, ou -e/-l/-p/--profile sans argument, arrête l'analyse et affiche l'en-tête, le message d'erreur, l'usage puis l'aide, avant de quitter en erreur.

Ordre d'exécution réel

  1. L'en-tête (version, copyright) s'affiche si -v/--version est présent, ou si l'interpréteur va de toute façon entrer en mode interactif (voir plus bas) — dans ce dernier cas même sans -v.
  2. Le profil est chargé (sauf --no-profile), avant que la table args n'existe encore — un script de profil n'a donc pas accès à args.
  3. La table globale args est construite.
  4. Chaque -e/-l fourni est exécuté, dans l'ordre où il apparaît sur la ligne de commande. Si l'un d'eux échoue, l'interpréteur s'arrête immédiatement (le reste, y compris script, n'est pas exécuté).
  5. Si un script a été fourni, il est chargé et exécuté (ou résolu comme commande de paquet — voir plus bas).
  6. Si le mode interactif doit s'enclencher (voir plus bas), le REPL démarre.

Le mode interactif s'enclenche si -i/--interactive est passé explicitement, ou si aucun script n'a été fourni et qu'aucun -e n'a été utilisé (un -l seul, sans -e ni script, entraîne donc aussi le REPL).

La table globale args

À l'image de la table arg du Lua standalone, yes.exe construit une table globale args avant d'exécuter -e/-l/le script :

Exemple : yes.exe monscript.yes arg1 arg2 produit args[-1] = "yes.exe", args[0] = "monscript.yes", args[1] = "arg1", args[2] = "arg2".

Quand script est résolu comme commande d'un paquet plutôt que comme fichier littéral (voir plus bas), args est reconstruite une seconde fois une fois la commande localisée : args[0] devient alors le chemin réel de command.yes exécuté, à la place du nom du paquet tapé sur la ligne de commande.

Le profil

Avant tout autre code (-e, -l, script), yes.exe charge un fichier de profil, dans l'esprit d'un .bashrc : utile pour définir des alias, des fonctions utilitaires ou pré-charger des bibliothèques qu'on veut disponibles à chaque session.

Résolution paquet/commande (yes.exe nom)

Quand un script est fourni et n'est pas --command/-c, yes.exe tente d'abord de l'ouvrir comme un fichier littéral. Si ce fichier n'existe pas (ou si -c/--command a forcé l'autre chemin), il tente de résoudre nom comme un paquet YScript :

  1. Recherche de nom via package.path, puis package.dotnetpath (la même résolution que require utilise en interne, via package.searchpath) — s'il n'est trouvé dans aucun des deux, l'échec final se comporte comme un fichier introuvable ordinaire (même message qu'un script inexistant).
  2. Si un module nom est trouvé, yes.exe cherche un fichier command.yes à la racine du même dossier. S'il n'y en a pas, l'erreur « le paquet 'nom' n'expose pas de commande. » est affichée et l'interpréteur s'arrête.
  3. Sinon, le paquet est chargé normalement (require("nom"), comme -l nom — package.loaded["nom"] est donc disponible à command.yes), la table args est reconstruite (voir plus haut), puis command.yes est exécuté comme s'il s'agissait du script littéral fourni.

-c/--command force ce chemin de résolution d'entrée, sans même essayer d'ouvrir script comme fichier littéral au préalable — utile si un fichier et un paquet portent le même nom, ou pour être explicite dans un script/alias.

Le détail de la résolution package.path/package.dotnetpath est documenté dans la bibliothèque package ; cette page ne couvre que l'usage côté ligne de commande. Pour installer/publier des paquets (au sens ypack.json, distinct d'un simple module require-able), voir la documentation du module ypack (require("ypack") ou yes.exe ypack doc ypack).

Le mode interactif (REPL)

Le comportement du moteur REPL (ScriptReplEngine, saisie multi-ligne, invite prompt/_PROMPT/ _PROMPT2, ...) est documenté côté embarqueur dans Démarrage ; yes.exe en est simplement un client, avec l'édition de ligne, l'historique et l'affichage propres à un terminal.

Du point de vue utilisateur :

Débogage

-d, -D ou --debug active l'affichage d'informations de déboguage, aussi bien pour l'exécution d'un script que dans le REPL. Une build DEBUG de l'exécutable lui-même active ce mode d'office.

debug.debug()

Contrairement au reste de la bibliothèque debug, debug.debug() n'est pas définie par le moteur cœur — stdin/stdout interactifs sont propres à l'hôte — mais ajoutée par yes.exe lui-même, qui a un vrai terminal.

Appelée, elle suspend le script à l'endroit de l'appel et ouvre une invite imbriquée (debug>), qui lit et exécute des lignes comme le REPL top-level (mêmes règles de saisie multi-ligne, historique, Ctrl+C annule la ligne en cours) :

local function f(x)
    local y = x * 2
    debug.debug()   -- suspend ici
    return y
end
print(f(21))
debug> print("bonjour depuis l'invite imbriquée")
bonjour depuis l'invite imbriquée
debug> cont
42

Taper cont (seul sur la ligne) ou atteindre la fin de l'entrée (EOF) reprend l'exécution normale du script à partir d'où elle avait été suspendue.

Comme en Lua, cette invite n'a pas de résolution automatique vers les variables locales de la fonction interrompue — une ligne tapée y est un chunk indépendant, exécuté dans l'environnement global. Pour inspecter/modifier l'état de l'appelant, passez explicitement par debug.getlocal/ debug.setlocal (voir debug) avec le niveau de pile approprié — celui-ci dépend de l'empilement interne (l'invite elle-même, plus l'appel natif de debug.debug, ajoutent chacun un niveau) et se détermine au besoin avec debug.getinfo :

debug> for lvl = 0, 5 do local i = debug.getinfo(lvl, "nSl"); if i then print(lvl, i.what, i.name) end end
debug> print(debug.getlocal(3, 2))   -- le niveau qui correspond à 'f' dans l'exemple ci-dessus
y	42