[JAVA] Road to REPL (?) Creation (1)

Introduction

For the time being, I will try to create REPL in Java 8.

REPL (Read (read input) --Eval (execution) --Print (result printing) -Loop (loop of 3 functions on the left)) is an environment to execute a program interactively, mainly Python. It is a function that is familiar to the script program and Common Lisp. In addition, console tools (such as SQLPlus) that come with the DBMS have similar functionality in terms of interpreting and executing input and outputting the results.

We'll create the foundation for a Java console program, rather than the interactive shell of the programming language, rather than the latter, the REPL in the broader sense.

I referred to the following article. (Sorry for the delay in description) Create a REPL (Read-eval-print loop).

important point

Requirements

First, the requirements for the REPL to be created.

--Implement only Java 8 functions. (Do not use the SDK and libraries that need to be downloaded separately) --The main focus is not on the execution environment of the program language, but on the interface that calls Java programs internally. --The first word of the input string becomes the command name.

Program style

Please note that it is an oleore style that deviates from the general description of Java. There are the following reasons. It is a reprint + α of the previous entry, Making lexical analysis with Java 8 (1).

--To keep the upper program simple, do not throw exceptions or return nulls as much as possible. I want to avoid burying the processing body in a large number of error checks. --Minimize scope. --Use immutable objects wherever possible. --Do not use general getters and setters. (Getter / Setter is evil. That's it. Original [Getters / Setters. Evil. Period.](Https: See //www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html) --No annotations to make the source compact. --In principle, the import statement is not used in order to get used to the Java standard library and to clarify the location of the function. Importing Stream-related classes, which tend to be redundant. --In order to reduce the number of source files, small classes and interfaces may be combined into one file. ―― ~~ Because I am tired of the long and deep nesting sentences at work, I often use ~~ early returns.
Surprisingly, there are many negatives, but I use it to check errors during processing, prevent the flow of the processing body from being buried by deep nesting, or because I want you to read the return at the beginning of the method as an expression. I am.

BaseREPL class

When writing the article, I was wondering whether to explain it from the top down or the bottom up, but to clarify the whole picture, I will explain from the top. If you come across a class name that you don't know, please look at it with the feeling of "I'm going to explain the details from now on?"

First, the big picture of the abstract class BaseREPL.

BaseREPL.java


abstract class BaseREPL {
   enum States {
        Quit,           //End
        Finished,       // Cleanup()Done
        Error,          //error
        NotFind,        //No target command
        Input,          //input(default)
        Incomplete,     //Input not completed(Used to support multi-line input)
        Complete,       //input completed
    }

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

    /**Main loop.(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);    //Prompt display / input reception
    abstract protected States eval(String input);       //Input character string interpretation / execution
    abstract protected States response(States state);   // eval()Post-processing
    abstract protected void   cleanup();                //Clean up at the end of the REPL

    abstract protected void welcome();                  //Display of REPL start string
    abstract protected void goodbye();                  //Display of REPL end string
    abstract protected void help();                     //Display help string

    // 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;
}

Commentary

A description of the source. However, because it is an abstract class, it is almost empty.

constructor

** Added on October 28, 2018 ** Added a constructor that receives the console encoding name. If null or whitespace is passed, it defaults to "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_;

Main loop

The main loop is a fixed process.

enum statesIs an enumeration that represents the state of the repl. This class uses only States.Finished and States.Quit. The other enumerators have not been decided how to use them, despite the comments. You can use it as you like at the inheritance destination. (I can't think of any use other than States.input, States.Error, and States.Missing ...)

Since it is assumed that cleanup () will clean up the used objects and resources, once the run () method is exited, there is a high possibility that it will end abnormally due to lack of resources, so at the beginning of the method I have checked whether it has been completed. Also, as I wrote in the notes, I will describe in a style that does not throw exceptions as much as possible, but even if an exception occurs without stopping, cleanup () is surely executed so that the processing body is `try Enclose it in {} ``` and put the cleanup () method call in the` finally {} ``` clause. Therefore, do not use exit ().

    enum States {
        Quit,           //End
        Finished,       // Cleanup()Done
        Error,          //error
        NotFind,        //No target command
        Input,          //input(default)
        Incomplete,     //Input not completed(Used to support multi-line input)
        Complete,       //input completed
    }

    /**Main loop.(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;

User-defined methods

The methods contained here are classes that must be implemented by a class that inherits from BaseREPL. I've explained what the method does in the main loop, so I'll omit it.

help()Is not used in the main loop. This methodeval()So, when it is interpreted as displaying help, and when supporting help text, implement it in the inherited class.

python


    abstract protected String accept(String prompt);    //Prompt display / input reception
    abstract protected States eval(String input);       //Input character string interpretation / execution
    abstract protected States response(States state);   //Post-eval post-processing
    abstract protected void   cleanup();                //Clean up at the end of the REPL

    abstract protected void welcome();                  //Display of REPL start string
    abstract protected void goodbye();                  //Display of REPL end string
    abstract protected void help();                     //Display help string

Output service method

A method that provides output to the console. All method names are unified to print, and 4 types of overloads depending on the argument type are prepared.

These methods eventually delegate processing to the Interface.Console object. This object will be explained at a later date (probably next time).

    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_;

Summary

The above is the explanation of the base class of REPL.

As you can see from the source, the `run ()` method is 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 It corresponds to Template Method of% B3). To express it, it is defined as an abstract class, not as an interface. In addition to this, methods that do not depend on the implementation of the inheritance destination have been implemented with the final qualifier.

Based on this abstract class, I would like to go with a concrete implementation of the REPL class next time, but since I have various desires, I plan to create a mechanism to be used in the inherited class.

Road to REPL (?) Creation (2)

Recommended Posts

Road to REPL (?) Creation (1)
Road to REPL (?) Creation (2)
19 Corresponds to object creation
Road to Java SE 11 Silver acquisition
Y-shaped road tour (how to write)
The road from JavaScript to Java
[Docker] Operation up to container creation # 2
to_ ○
The road to creating a music game 2
Java SE8 Silver ~ The Road to Pass ~
Introduction to kotlin for iOS developers ⑥-Kotlin creation
The road to creating a music game 3
The road to creating a music game 1