Similarly, it is difficult to pass lexical
scoping through an API, because host
functions cannot be lexically inside
scripting functions.
A key ingredient in the API for an
embeddable language is an eval
function, which executes a piece of
code. In particular, when a scripting
language is embedded, all scripts are
run by the host calling eval. An eval
function also allows a minimalist approach for designing an API. With an
adequate eval function, a host can
do practically anything in the script
environment: it can assign to variables (eval”a = 20”), query variables
(eval”return a”), call functions
(eval”foo( 32,’stat’)”), and so on.
Data structures such as arrays can
be constructed and decomposed by
evaluating proper code. For example,
again assuming a hypothetical eval
function, the C code shown in Figure
1 would copy a C array of integers into
the script.
Despite its satisfying simplicity
and completeness, an API composed
of a single eval function has two
drawbacks: it is too inefficient to be
used intensively, because of the cost
of parsing and interpreting a chunk
at each interaction; and it is too cumbersome to use, because of the string
manipulation needed to create commands in C and the need to serialize
all data that goes through the API.
Nevertheless, this approach is often
used in real applications. Python calls
it “Very High-Level Embedding.” 8
creDIt tk IllustratIon By J.f. PoDeVIn
For a more efficient and easier-to-use API, we need more complexity.
Besides an eval function for executing scripts, we need direct ways to call
functions defined by scripts, to handle errors in scripts, to transfer data
between the host program and the
scripting environment, and so on. We
will discuss these various aspects of
an API for an embeddable language
and how they have affected and been
affected by the design of Lua, but first
we discuss how the simple existence
of such an API can affect a language.
Given an embeddable language
with its API, it is not difficult to write
a library in the host language that ex-
ports the API back into the scripting
language. So, we have an interesting
form of reflection, with the host lan-
guage acting as a mirror. Several mech-
anisms in Lua use this technique. For
example, Lua offers a function called
type to query the type of a given val-
ue. This function is implemented in
C outside the interpreter, through an
external library. The library simply
exports to Lua a C function (called
luaB _ type) that calls the Lua API to
get the type of its argument.
Control
The first problem related to control
that every scripting language must
solve is the “
who-has-the-main-function” problem. When we use the
scripting language embedded in a
host, we want the language to be a library, with the main function in the
host. For many applications, however,
we want the language as a standalone
program with its own internal main
function.
Lua solves this problem with the
use of a separate standalone program.
Lua itself is entirely implemented as a
library, with the goal of being embedded in other applications. The lua
command-line program is just a small
application that uses the Lua library
as any other host to run pieces of Lua
code. The code in Figure 2 is a bare-bones version of this application. The
real application, of course, is longer
than that, as it has to handle options,
errors, signals, and other real-life details, but it still has fewer than 500
lines of C code.
Although function calls form the