Design: Embedding Lua in script

In this article, we describe the initial design of lscript and how we can modify it to embed a programming language.

The design of lscript

The C code for lscript uses interposition to forward and log shell I/O. The code uses some helper functions to perform the forwarding. Specifically:

  • When lscript receives user input, it sends the input to the underlying program by passing the input to the writetosubprocess function.
  • When lscript receives program output, it:

    • sends the output to the user by passing the output to the writetouser function
    • writes the output to a log file by passing the output to the writetolog function

Original Structure of the C Code

In general, anything intended for the the underlying program goes through writetosubprocess; anything coming from the underlying program goes through writetouser and writetolog.

The goal of this assignment is to make lscript more extensible by embedding the Lua programming language within it. As part of the embedding, the normal forwarding logic we just described will be rewritten so that it is handled by a separate (and replaceable!), interpreted program.

Why Lua?

Typically, the languages most amenable to embedding are “scripting languages”. Scripting languages that support embedding in C programs include Python, Perl, Ruby, JavaScript, Lua, and numerous others. But some are more amenable to the task than others. Python, Perl, and Ruby are large (for example, the Python interpreter is over 100 times the size of the lscript program), are typically not written with ease of embedding foremost, and are not actually very fast interpreters (which may not matter for our example, but might in some other program). Modern JavaScript implementations can be quite fast, but often even larger (e.g., 200 times the size of the lscript program).

In contrast, Lua is compact, relatively speedy for an interpreter, and was designed to be easy to embed. Unlike some other languages that claim to be designed for ease of embedding, Lua is small without being hard to program or lacking in expressiveness.

Redesigning lscript to embed Lua

The version of lscript with embedding will modify the lscript interposition in the following way:

  • When lscript receives user input, it sends the input to a Lua function userInputEvent.
  • When lscript receives program output, it sends the input to a Lua function subprocessOutputEvent.

These two Lua functions can do whatever we want. You are given a default script where userInputEvent just passes its input unmodified to the C function writetosubprocess, and where subprocessOutputEvent passes its input to both C functions writetouser and writetolog. This just replicates the original behavior of the program. But now we have the flexibility to change the “brains” of the code without recompiling the C code, just by editing the Lua script and restarting the program.

Our Goal: Moving the Program Logic into Lua Code