L'hôte (IScriptHost)

Le moteur est volontairement agnostique de son environnement d'exécution : tout ce qui touche au monde extérieur — système de fichiers, flux standard, horloge, variables d'environnement, exécution de commandes — passe par YScript.Hosting.IScriptHost. ScriptEngine/Runtime.ScriptState appelle cette interface, jamais l'API .NET directement, pour toute opération de ce type demandée par un script (io.*, os.*, require d'un chemin, ...).

Un hôte se fournit au constructeur :

using var engine = new ScriptEngine(myHost, options);

Si aucun hôte n'est fourni, YScript.Hosting.DefaultHost est utilisé. Il est pensé pour un usage embarqué/sandboxé plutôt que pour un outil en ligne de commande :

L'interpréteur en ligne de commande (voir L'interpréteur) illustre l'écart type entre un hôte sandboxé et un hôte "plein accès" : son hôte ConsoleHost hérite de DefaultHost et ne redéfinit que ce qui doit se comporter comme un vrai terminal — stdout/stderr câblés sur Console.Out/Console.Error, HasCommandShell => true avec ExecuteCommand/OpenProcessPipe lançant réellement un process shell (cmd.exe//bin/sh), HasProcessCultureControl => true (un vrai terminal laisse l'utilisateur changer sa propre locale), et un nom d'encodage "oem" supplémentaire propre à Windows.

Ce qu'un hôte personnalisé implémente

IScriptHost se découpe en quatre familles, chaque méthode documentant dans son commentaire XML par quelle fonction de bibliothèque standard elle est appelée :

La façon la plus simple de personnaliser un hôte est d'hériter de DefaultHost et de ne redéfinir (virtual) que ce qui diffère — comme le fait ConsoleHost — plutôt que de réimplémenter IScriptHost intégralement.

Exemple : rediriger la sortie standard vers un composant applicatif

public class UiHost : DefaultHost
{
    readonly Action<string> _onOutput;
    IFileHandle _stdout;

    public UiHost(Action<string> onOutput) => _onOutput = onOutput;

    public override IFileHandle StandardOutput =>
        _stdout ??= new TextIOFileHandle("stdout", FileAccessMode.Write,
            writer: new ActionTextWriter(_onOutput));
}

(ActionTextWriter serait un petit TextWriter maison qui relaie chaque écriture à _onOutput — non fourni par le moteur.)

Exemple : terminer seulement le script, pas le process

DefaultHost.Exit appelle Environment.Exit — adapté à un outil CLI, pas à un moteur embarqué dans une application plus large où os.exit() ne doit arrêter que le script en cours :

public override void Exit(int exitCode)
    => throw new ScriptExitRequestedException(exitCode); // à capturer autour de l'exécution du script