Jx9 Scripting Engine

An Embeddable Scripting Engine



An Introduction To The Jx9 C/C++ Interface.

This article provides an overview and roadmap to the C/C++ interface to Jx9.


Early versions of the Jx9 engine were very easy to learn since they only supported 14 C/C++ interfaces. But as the Jx9 scripting engine has grown in capability, new C/C++ interfaces have been added so that now there are over 80 distinct APIs. This can be overwhelming to a new programmer. Fortunately, most of the C/C++ interfaces in the Jx9 engine are very specialized and never need to be used. Despite having so many entry points, the core API is still relatively simple and easy to code to. This article aims to provide all of the background information needed to easily understand how the Jx9 engine works.


A separate document, The Jx9 engine C/C++ Interface, provides detailed specifications for all of the various C/C++ APIs for the Jx9 engine. Once the reader understands the basic principles of operation for the Jx9 engine, that document should be used as a reference guide. This article is intended as introduction only and is neither a complete nor authoritative reference for the Jx9 API.

1.0 Core Objects And Interfaces

The principal task of a Jx9 engine is to compile and execute Jx9 code. In order to accomplish this purpose, the developer needs to know about two objects:

Jx9 engine Handle

typedef struct jx9 jx9;

Each active Jx9 engine is represented by a pointer to an instance of the opaque structure named "jx9". It is useful to think of an jx9 pointer as an object.

The jx9_init() interface is its constructor and jx9_release() is its destructor.

There is also the jx9_config() interface which is used to configure a working jx9 engine instance.

The most important interfaces are the compile interfaces: jx9_compile() and jx9_compile_file(). That is, these interfaces takes as their input a Jx9 program to compile and produces Jx9 bytecodes represented by an opaque pointer to the jx9_vm structure (see below for more information on this structure).

Jx9 virtual machine Object

typedef struct jx9_vm jx9_vm;

An instance of this object represents a compiled Jx9 program. this structure hold the Jx9 bytecode program resulting from successful compilation of the target Jx9 script using one of the compile interfaces.

The life of a Jx9 virtual machine goes something like this:

  1. Compile your Jx9 script using one of the jx9_compile() or jx9_compile_file() interfaces. On successful compilation, the Jx9 engine will automatically create an instance of this structure (jx9_vm) and a pointer to this structure is made available to the caller.

  2. When something goes wrong while compiling the Jx9 script due to a compile-time error, the caller must discard this pointer and fix its erroneous Jx9 code. Compile-time error messages can be extracted via a call to jx9_config().

  3. Optionally, Configure the virtual machine using the jx9_vm_config() interface with it's many configuration verbs, but the most important option is set via the Jx9_VM_CONFIG_OUTPUT verb which is used to register a VM output consumer callback. That is, an user defined function responsible of consuming the VM output such as redirecting it [i.e: the VM output] to the standard output (STDOUT), to a disk file or sending it back to the connected peer and so forth.

  4. Optionally, register one or more foreign functions or constants using the jx9_create_function() or jx9_create_constant() interfaces.

  5. Execute the compiled Jx9 program by calling jx9_vm_exec().

  6. Optionally, extract the contents of one or more variables declared inside your Jx9 script using the jx9_vm_extract_variable() interface.
  7. Reset the virtual machine using jx9_vm_reset() then go back to step 5. Do this zero or more times.

  8. Destroy the virtual machine using jx9_vm_release().

Refer to documentation on individual methods above for additional information.


The Jx9 engine and the Jx9 virtual machine objects are controlled by a small set of C/C++ interface routine listed below:


int jx9_init(jx9 **ppEngine);

int jx9_config(jx9 *pEngine, int nConfigOp, ...);

int jx9_release(jx9 *pEngine);


int jx9_compile(jx9 *pEngine, const char *zSource, int nLen, jx9_vm **ppOutVm);

int jx9_compile_file(jx9 *pEngine, const char *zFilePath, jx9_vm **ppOutVm, int iFlags);


int jx9_vm_config(jx9_vm *pVm, int iConfigOp, ...);

int jx9_vm_exec(jx9_vm *pVm, int *pExitStatus);

jx9_value * jx9_vm_extract_variable(jx9_vm *pVm, const char *zVarname);

int jx9_vm_reset(jx9_vm *pVm);

int jx9_vm_release(jx9_vm *pVm);


The ten C/C++ interface routines and two objects listed above form the core functionality of Jx9. The developer who understands them will have a good foundation for using Jx9. Here is a summary of what the core interfaces do:


jx9_init()

This routine create, initialize and returns a new Jx9 engine instance. This is often the first Jx9 API call that an application makes and is a prerequisite in order to compile Jx9 code using one of the compile interfaces.

jx9_compile()

jx9_compile_file()

To execute Jx9 code, it must first be compiled into a bytecode program using one of these routines.

These routine takes as their input a Jx9 program to compile and produce Jx9 bytecodes represented by an opaque pointer to the jx9_vm structure.

These APIs does not actually evaluate the Jx9 code. They merely prepares the Jx9 code for later execution.

When something goes wrong while compiling the Jx9 script due to a compile-time error, the caller must discard the jx9_vm pointer and fix it's erroneous Jx9 code.

The compile-time error log can be extracted using the jx9_config() interface with a configuration verb set to Jx9_CONFIG_ERR_LOG.

jx9_vm_config()

After successful compilation of the target Jx9 script, this is the first API function you should call. This interface is used to configure a working virtual machine. There are so many configuration verbs but the most importants are:

Jx9_VM_CONFIG_OUTPUT which is used to register a VM output consumer callback. That is, an user defined function responsible of consuming the VM output such as redirecting it to the standard output (STDOUT) or sending it back to the connected peer and so on.

Jx9_VM_CREATE_VAR which is used to install one or more foreign variables so that the host application can share informations with the running Jx9 script.

jx9_vm_exec()

This routine is used to execute Jx9 bytecode program resulting from successful compilation of the target Jx9 script using one of the compile interfaces.

jx9_vm_reset()

This routine is used to reset the virtual machine to it's initial state so that the compiled program can be re-executed again.

jx9_vm_extract_variable() This powerful interface is used to extract the contents of one more variables declared inside your Jx9 script.

jx9_vm_release()

This routine destroy a working Jx9 virtual machine. Every virtual machine must be destroyed using a call to this routine in order to avoid memory leaks.

jx9_release()

This routine destroy a working Jx9 engine created by a prior call to jx9_init(). Every Jx9 engine must be destroyed using a call to this routine in order to avoid memory leaks.

3.0 Typical Usage of Core Routines and interfaces

An application that wants to use Jx9 will typically use jx9_init() to create a new Jx9 engine instance. After that, to run Jx9 scripts, it must be first compiled to Jx9 bytecode program using one of the compile interface such as jx9_compile() or jx9_compile_file().


After successful compilation, the virtual machine should be configured using the jx9_vm_config() interface for example to install a VM output consumer callback or  one or more foreign variables to share informations between the host application and the underlying Jx9 VM.


Now call jx9_vm_exec() one or more times to execute your compiled Jx9 program. After that, you can extract the contents of one more variables declared inside your Jx9 script using the jx9_vm_extract_variable() interface.


When done call jx9_vm_release() and jx9_release() to destroy respectively the virtual machine and the jx9 engine handle.

3.0 In-Process Extending

Jx9 includes interfaces that can be used to extend its functionality. Such routines includes jx9_create_function() and jx9_create_constant().


The jx9_create_function() interface is used to install a foreign function (typically a C/C++ function) that can be invoked from your Jx9 code. The new function implementation typically makes use of the following additional interfaces.


All of the built-in Jx9 functions (over 303) of Jx9 such as is_string(), crc32(), json_encode(), utf8_decode(), etc. are created using exactly this interface.

Refer to the following tutorial for a step by step guide on how to create, install and call foreign functions from your Jx9 script.


The jx9_create_constant() interface is used to associate a constant name (An identifier in the Jx9 world such as Jx9_EOL, Jx9_OS, PI, etc.) with a C callback which is responsible of expanding the constant name to the desired value such as 3,14 the value of PI.

Refer to the following tutorial for a step by step guide on how to create, install and expand constants from your Jx9 code.

4.0 Others Interfaces

This article only mentions the foundational Jx9 interfaces. The Jx9 library includes many other APIs implementing useful features that are not described here. A complete list of functions that form the Jx9 application programming interface is found at the C/C++ Interface Specification. Refer to that document for complete and authoritative information about all Jx9 interfaces.


Symisc Systems
Copyright © Symisc Systems