[JAVA] Road to REPL (?) Création (1)

introduction

Pour le moment, je vais essayer de créer REPL en Java 8.

REPL (Read (lecture d'entrée) --Eval (exécution) --Print (impression des résultats) -Loop (boucle de 3 fonctions à gauche)) est un environnement pour exécuter des programmes de manière interactive, principalement Python. C'est une fonction familière dans le programme de script et Common Lisp. En outre, les outils de console (tels que SQLPlus) fournis avec le SGBD ont des fonctions similaires en termes d'interprétation et d'exécution des résultats d'entrée et de sortie.

Nous allons créer la base d'un programme de console Java, plutôt que ce dernier, plutôt que le REPL plutôt large, plutôt que le shell interactif du langage de programmation.

J'ai fait référence à l'article suivant. (Désolé pour le retard dans la description) Créer une REPL (boucle de lecture-évaluation-impression).

point important

Exigences

Tout d'abord, les conditions requises pour la création de la REPL.

--Implémenter uniquement les fonctions Java 8. (N'utilisez pas le SDK et les bibliothèques qui doivent être téléchargés séparément)

Style de programme

Veuillez noter qu'il s'agit d'un style oléore qui s'écarte de la description générale de Java. Il y a les raisons suivantes. Il s'agit d'une réimpression + α de l'entrée précédente, Création d'une analyse de phrase avec Java 8 (Partie 1).

Classe BaseREPL

Lors de la rédaction de l'article, je me demandais s'il fallait l'expliquer de haut en bas ou de bas en haut, mais pour clarifier le tableau dans son ensemble, je vais l'expliquer du haut. Si vous rencontrez un nom de classe que vous ne connaissez pas, regardez-le avec le sentiment "Je vais vous expliquer les détails à partir de maintenant?"

Tout d'abord, une vue d'ensemble de la classe abstraite BaseREPL.

BaseREPL.java


abstract class BaseREPL {
   enum States {
        Quit,           //Fin
        Finished,       // Cleanup()Terminé
        Error,          //Erreur
        NotFind,        //Aucune commande cible
        Input,          //contribution(default)
        Incomplete,     //Entrée incomplète(Utilisé pour prendre en charge l'entrée multiligne)
        Complete,       //entrée terminée
    }

    BaseREPL(String encoding) {
        if ( encoding == null  ||  encoding.trim().isEmpty() ) { encoding = "UTF-8"; }
        console_ = Service.Console.create(encoding);
    }

    /**Boucle principale.(template method) */
    public final void run() {
        if ( state_ == States.Finished ) { return; }

        try {
            welcome();
            while (state_ != States.Quit) {
                state_ = response( eval( accept(prompt_) ) );
            }
            goodbye();
        } finally {
            cleanup();
            state_ = States.Finished;
        }
    }

    // user defined methods ==========================================================================
    abstract protected String accept(String prompt);    //Affichage rapide / réception d'entrée
    abstract protected States eval(String input);       //Interprétation / exécution de la chaîne de caractères d'entrée
    abstract protected States response(States state);   // eval()Post-traitement
    abstract protected void   cleanup();                //Nettoyer à la fin de REPL

    abstract protected void welcome();                  //Affichage de la chaîne de caractères de début de REPL
    abstract protected void goodbye();                  //Affichage de la chaîne de caractères de fin de REPL
    abstract protected void help();                     //Afficher la chaîne d'aide

    // print strings to console ======================================================================
    public final void print(String format, Object... args)   { console_.print(format, args);     }
    public final void print(String s)                        { console_.print(s);                }
    public final void print(String[] sz)                     { for (String s : sz) { print(s); } }
    public final void print(java.util.Collection<String> sz) { for (String s : sz) { print(s); } }

    // internal fields ===============================================================================
    protected final Interface.Console console_ = Service.Console.get();
    protected       String prompt_ = "REPL> ";
    protected       States state_ = States.Input;
}

Commentaire

Une description de la source. Cependant, comme il s'agit d'une classe abstraite, elle est presque vide.

constructeur

** Ajouté le 28 octobre 2018 ** Ajout d'un constructeur qui reçoit le nom d'encodage de la console. Si nul ou vide est passé, la valeur par défaut est "UTF-8".

python


    BaseREPL(String encoding) {
        if ( encoding == null  ||  encoding.trim().isEmpty() ) { encoding = "UTF-8"; }
        console_ = Service.Console.create(encoding);
    }

    protected final Interface.Console console_;

Boucle principale

La boucle principale est un processus fixe.

enum statesEst un type d'énumération qui représente l'état de repl. Cette classe utilise uniquement States.Finished et States.Quit. Les autres enquêteurs n'ont pas encore décidé comment les utiliser, malgré les commentaires. Vous pouvez l'utiliser comme vous le souhaitez à la destination d'héritage. (Je ne peux penser à aucune autre utilisation que States.input, States.Error et States.Missing ...)

Comme il est supposé que cleanup () nettoiera les objets et les ressources utilisés, une fois la méthode run () quittée, il y a de fortes chances qu'elle se termine anormalement en raison d'un manque de ressources, donc au début de la méthode J'ai vérifié s'il était terminé. Aussi, comme je l'ai écrit dans les notes, je vais le décrire dans un style qui ne lève pas autant que possible des exceptions, mais même si une exception se produit sans s'arrêter, le corps de traitement est essayez '' de sorte que cleanup () est sûrement exécuté. Placez-le dans {} et placez l'appel à la méthode cleanup () dans la clause`` finally {}` ``. Par conséquent, n'utilisez pas exit ().

    enum States {
        Quit,           //Fin
        Finished,       // Cleanup()Terminé
        Error,          //Erreur
        NotFind,        //Aucune commande cible
        Input,          //contribution(default)
        Incomplete,     //Entrée incomplète(Utilisé pour prendre en charge l'entrée multiligne)
        Complete,       //entrée terminée
    }

    /**Boucle principale.(template method) */
    public final void run() {
        if ( state_ == States.Finished ) { return; }

        try {
            welcome();
            while (state_ != States.Quit) {
                state_ = response( eval( accept(prompt_) ) );
            }
            goodbye();
        } finally {
            cleanup();
            state_ = States.Finished;
        }
    }

    protected String prompt_ = "REPL> ";
    protected States state_ = States.Input;

Méthode définie par l'utilisateur

Les méthodes contenues ici sont des classes qui doivent être implémentées par des classes qui héritent de BaseREPL. J'ai expliqué ce que fait la méthode dans la boucle principale, je vais donc l'omettre.

help()N'est pas utilisé dans la boucle principale. Cette méthodeeval()Lorsqu'il est interprété comme affichant de l'aide et lorsqu'il prend en charge le texte d'aide, il est implémenté dans la classe héritée.

python


    abstract protected String accept(String prompt);    //Affichage rapide / réception d'entrée
    abstract protected States eval(String input);       //Interprétation / exécution de la chaîne de caractères d'entrée
    abstract protected States response(States state);   //Post-traitement après évaluation
    abstract protected void   cleanup();                //Nettoyer à la fin de REPL

    abstract protected void welcome();                  //Affichage de la chaîne de caractères de début de REPL
    abstract protected void goodbye();                  //Affichage de la chaîne de caractères de fin de REPL
    abstract protected void help();                     //Afficher la chaîne d'aide

Méthode de service de sortie

Une méthode qui fournit une sortie à la console. Tous les noms de méthode sont unifiés pour être imprimés et 4 types de surcharges sont préparés en fonction du type d'argument.

Ces méthodes délèguent finalement le traitement à l'objet Interface.Console. Cet objet sera expliqué à une date ultérieure (probablement la prochaine fois).

    public final void print(String format, Object... args)   { console_.print(format, args);     }
    public final void print(String s)                        { console_.print(s);                }
    public final void print(String[] sz)                     { for (String s : sz) { print(s); } }
    public final void print(java.util.Collection<String> sz) { for (String s : sz) { print(s); } }

    protected final Interface.Console console_;

Résumé

Ce qui précède est l'explication de la classe de base de REPL.

Comme vous pouvez le voir à partir de la source, la méthode run () '' est GoF [design pattern](https: // qiita. com / tags /% E3% 83% 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E3% 83% 91% E3% 82% BF% E3% 83% BC% E3% 83 Cela correspond à la Méthode modèle de% B3). Pour l'exprimer, il est défini comme une classe abstraite et non comme une interface. De plus, des méthodes qui ne dépendent pas de l'implémentation de la destination d'héritage ont été implémentées avec le modificateur final.

Sur la base de cette classe abstraite, j'aimerais aller avec l'implémentation d'une classe REPL concrète la prochaine fois, mais comme j'ai divers désirs, je prévois de créer un mécanisme à utiliser dans la classe héritée.

Route pour créer REPL (?) (2)

Recommended Posts

Road to REPL (?) Création (1)
Road to REPL (?) Création (2)
19 Correspond à la création d'objet
En route vers l'acquisition de Java SE 11 Silver
La route de JavaScript à Java
à_ ○
La route pour créer un jeu sonore 2
Java SE8 Silver ~ La route à franchir ~
Introduction à kotlin pour les développeurs iOS ⑥ ー création de kotlin
La route pour créer un jeu sonore 3
La route pour créer un jeu sonore 1