[Java] Kinx Library-REPL

11 minute read

Kinx Library-REPL


The script language Kinxdeliveredby”“ItlookslikeJavaScript,thebrain(contents)isRuby,(stabilityisAC/DC)”). The library is the language. So how to use the library.

This time it is REPL.

At first, I was pessimistic that I couldn’t do a REPL, but somehow I made something that works like that, so it’s an introduction.

Because, if you run evel obediently, the code area will swell up every time you run it once, so Isolate is executed in another context. Doing so dramatically improved memory usage.

However, in this case, the context is different and objects cannot be passed. I managed to manage this by passing the class definition and function definition to eval every time. as a result,,,

  1. It is now usable as a computer.
  2. Functions (function/native), classes and modules can be used as they are.
  3. Escape sequences make ** colorful on Windows **.
  4. I also tried to do keyword completion with the [TAB] key.
  5. Support for East Asian Width. UTF8 characters can also be said as [BS] or [DEL]. At least Japanese is OK.

It was completed to the extent. Worked hard…

What is REPL?

“What is REPL?”, => Read-Eval-Print-Loop. The input is read, eval() (evaluated), the result is displayed, and so on.

How to use

starting method

REPL is built into Kinx itself like SpecTest. Do the following:

$ ./kinx --exec:repl
kinx[ 0]> _

The colors are different because they are written in Markdown here, but in reality, prompts, keywords, etc. are highlighted and displayed in color (for both Windows and Linux).

At first I put up an image to understand it, but it is still a demo, so I tried hard to make a demo. Please praise someone.


You can see that autocomplete (keyword completion) is also working properly. It’s difficult to understand without a demo here. seeing is believing.


To get started, try the ones listed here Ruby (start in 20 minutes). I’m glad that it’s about this good.

$ ./kinx --exec:repl
kinx[ 0]> "Hello, world"
=> "Hello, world"

kinx[ 1]> System.println("Hello, world")
Hello, world
=> (null)

kinx[ 2]> 3+2
=> 5

kinx[ 3]> 3*2
=> 6

kinx[ 4]> 3**2
=> 9

kinx[ 5]> Math.sqrt(9)
=> 3

kinx[ 6]> a = 3 ** 2
=> 9

kinx[ 7]> b = 4 ** 2
=> 16

kinx[ 8]> Math.sqrt(a+b)
=> 5

Then it is the main subject.

Command list

All commands start with ..

Command Content
.help Display help
.quit Exit
.history Display command history
.vars Display current variable list
.delete name Deletes the variable name from the current list of variables
.showdef name Shows the definition of a function or class
.cursor [*on/off] Cursor display ON/OFF (default ON)
.fullcode [on/*off] Full input mode (default OFF), do not execute until .run command is input
.time [on/*off] Execution time measurement mode (default OFF), display execution time after execution
.run Used to run in full input mode

Please be aware that Ctrl-C will also terminate it.

If you type .help, the following help will be displayed.

kinx[ 0]> .help
Kinx REPL Command: * means by default
    .help Display this help.
    .quit Quit REPL.
    .history Display command history.
    .vars Display variables with its value.
    .delete name Delete a variable by name.
    .showdef name Display function/class definition by name.
    .cursor [*on|off] Set to'off' to make the cursor invisible.
    .fullcode [on|*off] Set to'on', and the code will be executed by .run instead of immediately.
    .time [on|*off] Set to'on' to measure and display elapsed time.
    .run Execute the code only with .fullcode 1.

REPL Operation:
    [^] Arrow up Choose a previous command.
    [v] Arrow down Choose a next command.
    [<] Arrow left Move cursor to left.
    [>] Arrow right Move cursor to right.
    Ctrl+[<] Move cursor to left by word.
    Ctrl+[>] Move cursor to right by word.
    [DEL] Delete character on cursor.
    [BS] Delete previous character.
    [TAB] Move to the next tab stop, or auto-complete.

Move the cursor with the left and right of the cursor key, move with each word with Ctrl + left and right. You can browse the history with the up and down keys.

Line editor

Basically, the line editor accepts input and executes the input immediately.

kinx[ 0]> 10 * 2
=> 20

Automatic multi-line judgment and automatic indentation

It will automatically recognize the { and the corresponding } and continue in editor mode until the entire block has been entered. At this time, an indent for 4 spaces is automatically added depending on the number of {.

However, you can only edit that line, so you cannot edit it after entering [Enter].

Use this function to define function, class, module, etc.

kinx[ 0]> function func(...a) {
[1]> return a.reduce(&(r, e) => r + e);
=> function func

Then you can use the function like this:

kinx[ 0]> function func(...a) {[1]> return a.reduce(&(r, e) => r + e);
=> function func

kinx[ 3]> func(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
=> 55

You can check the registered function as follows.

kinx[ 4]> .vars
function func(...a)

kinx[ 5]> .showdef func
function func(...a) {
    return a.reduce(&(r, e) => r + e);

Keyword completion

For commands and keywords, press the [[TAB]` key to enter completion mode. Completion mode complements the string that may follow the preceding string with light gray. You can check it in the above demo that I made with all my might. However, it will be troublesome to return to the top, so I will post it again (because I made it).


Pressing the [TAB] key while this candidate is displayed will switch to the next candidate. At this time, the following key operations are performed.

  • Input of character … Completion mode is canceled once and the input character is added to the preceding character.
  • Enter blanks or symbols… Confirmed with the current candidate and the entered characters are added.
  • [BS], [DEL] keys… Confirm with the current candidate, and the cursor will wait for input at that position.
  • [Enter] key … Confirm on the spot and execute or move to the next line.

The candidates for completion change depending on the context of the position. For example, if it is estimated to be an array from past history, the method of Array etc. will be added to the candidates. Also, if you assign an object instantiated with the new operator in the past history, its class method etc. will be added to the candidates.

You can check a part of this execution example in the first demo. For example, value and sum are displayed as candidates for s. in the last line.

It may not work well in some cases, but if you enter a character string halfway and press the [TAB] key, candidates starting with that character string will appear in order, so try various things. Please give me.

Also, namespace is not supported.

Variable list

The .vars command displays a list of variables currently in effect. Note that function names and class names are treated in the same way as variable names, so you cannot register them with the same name. It will be overwritten with the one defined later.

kinx[ 20]> .vars
class Sample(...a)
a = 10
b = 20
c = 30
d = 40
e = 50
f = 60
g = 70
sample = new Sample(a, b, c, d, e, f, g)

Delete variable

You can specify the variables you no longer need with the .delete command and delete them. If you assign to the same variable name, it will be overwritten, so you may not have much opportunity to use it. However, there are cases where Compile Error is generated when the registration order of variables is incorrect due to repeated overwriting, or when the dependency of variables is incorrect due to the use of the .delete command. In such a case, delete the variable that became strange and register it again to make it work properly.

For example, there are cases in which the above variables are registered and are as follows.

kinx[ 25]> .delete g // delete g
kinx[ 26]> sample.sum() // g is gone, so the sample instance is malformed.
=> Error: Compile Error.

kinx[ 27]> .vars
class Sample(...a)
a = 10
b = 20
c = 30
d = 40
e = 50
f = 60
sample = new Sample(a, b, c, d, e, f, g) // <- Illegal form because g here is gone.

kinx[ 28]> g = 60 // I want to register a new g, but there is a compilation error.
=> Error: Compile Error.

kinx[ 29> .delete sample // Since the malformed instance is blocking the execution, delete it as well.
kinx[ 30]> g = 60 // g can be re-registered.
=> 60

kinx[ 31]> var sample = new Sample(a, b, c, d, e, f, g) // sample is also re-registered.
=> (null)

kinx[ 32]> sample.sum() // Can be executed using a new g.
=> 270

Display function, class and module definitions

In .vars, the function name and class name are displayed in the list, but the definition is not displayed. You can then use the .showdef command to see the contents of the definition.

kinx[ 33]> .showdef Sample
class Sample(...a) {
    @value = a;
    public sum() {
        return @value.reduce(&(r, e) => r + e);

Execution history

You can check the execution history up to this point with the .history command. For example, the following is displayed (the number is different from the above example, but it is a sample).

From the past history, you can also execute reference by using ! as follows.

kinx[ 36]> !34
=> "sample.sum();"
=> 270

You can also select the history to be re-entered with the up and down cursor keys.

Execution time measurement

If you set .time on, the execution result will be displayed. Since the measurement result is simply the elapsed time until it returns with eval, various overheads are included, but it will be a guideline.

kinx[ 0]> native fib(n) {
    [1]> return n if (n <3);
    [2]> return fib(n-2) + fib(n-1);
=> native<int> fib

kinx[ 4]> .time on
.time: on

kinx[ 5]> fib(39)
=> 102334155

elapsed: 1.238 s

kinx[ 6]> fib(34)
=> 9227465

elapsed: 0.131 s

Full input mode

If you set .fullcode on, it will not be executed just by pressing the [Enter] key. Command input continues until you enter the .run command. However, at present, in the full input mode, registration of variables and class definitions are not done **. All will be a one-time execution of only that input.

kinx[ 0]> .fullcode on
.fullcode: on

kinx[ 1]> class Something() {
    [2]> public println(...a) {
    [3]> System.println(a);
    [6]> s = new Something();
    [7]> s.println(1, 2, 3, 4, 5, 6, 7, 8);
    [8]> .run
[1 2 3 4 5 6 7 8]
=> {"s":null}

kinx[ 9]> .vars

kinx[ 10]>

Read external file

Use the .load command to load an external file. Modules that are using as normal libraries are also loaded with .load. You can enable some method name completion by loading with .load.

For example, if you use DateTime you can do:

kinx[ 0]> .load DateTime
=> Successfully loaded.

kinx[ 1]> var dt = new DateTime(2020, 1, 1, 9, 30, 0)
=> (null)

kinx[ 2]> .vars
dt = new DateTime(2020, 1, 1, 9, 30, 00)

kinx[ 3]> dt.weekday()
=> 3

kinx[ 4]> System.println(dt)
2020/01/01 09:30:00

The search file name is specified name.kx. Search target is performed in the following order. So you can also refer to the standard library.

  1. Current directory2. In the lib folder under the folder containing the kinx executable file
  2. In the lib/std folder under the folder that contains the kinx executable file
  3. In the ../lib folder as seen from the folder that contains the kinx executable file
  4. In the kinxlib folder under the folder that contains the kinx executable file
  5. In the kinxlib/std folder under the folder that contains the kinx executable file

Sorry, the v0.9.2 release fails .load DateTime on Linux due to omissions (5 and 6 were required for Linux but not implemented yet). Specify .load /usr/bin/kinxlib/std/DateTime as a workaround. It’s tough. Excuse me.

However, there are currently two things to note about DateTime. It may improve in future versions.

  • You can create a DateTime object without using the new operator, but you must use the new operator for method name completion.
  • The current time is acquired with new DateTime(), but the value (time) to be acquired changes for each execution because a new new is executed for each execution.

East Asian Width

It supports input in UTF8. Since the cursor is moved according to the definition of East Asian Width, full-width characters move within that width. In the example below, even if you use AIUEO, the character moves in full-width one character at a time, and in AIWEO, the cursor moves in half-width. Also, deleting with the [DEL] or [BS] keys works correctly.

$ ./kinx --exec:repl
kinx[ 0]> a = "Aiueo Airio";
=> "Aiue Iwao"

kinx[ 1]> System.println(a);
=> (null)

kinx[ 2]> a = "I like it"; // Press [DEL] on "U" and press [BS] on "O".
=> "I like that"

kinx[ 3]> System.println(a);
That kind of aio
=> (null)

in conclusion

I read somewhere that a programming language is half a person without a REPL**, so I tried my best to make it (it was difficult…). That said, it is still developing. With this as the first edition, we would like to improve upon request.

It would be nice if more people could take this opportunity. The release build is also available, so if you like.

  • Repository … https://github.com/Kray-G/kinx
  • Releases… https://github.com/Kray-G/kinx/releases

See you next time.