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).
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)
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).
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;
}
Une description de la source. Cependant, comme il s'agit d'une classe abstraite, elle est presque vide.
** 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_;
La boucle principale est un processus fixe.
welcome () '', tout d'abord, un message d'accueil au démarrage de REPL.`, interpréter et exécuter la chaîne de caractères saisie avec` `ʻaccept ()`
.`response ()` `, exécutez le post-traitement après avoir reçu le résultat du traitement de```eval ()
`.
cleanup () '' pour nettoyer.enum states
Est 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;
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
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.
print (String, Object ...)
fournit une sortie formatée (équivalent à printf ()).
print (String) '' `` imprime la chaîne reçue + saut de ligne. Correspond à println ().
print (String [])
,
print (Collection
prend une collection de chaînes et imprime une ligne pour chaque élément de la collection.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_;
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.
Recommended Posts