Agate aims to be embedded in other applications like games. It has a C API to interact with the runtime environment of the Agate virtual machine.

The whole Agate API is in the agate.h header. You need to include it to have access to the features of Agate.

#include "agate.h"

Virtual Machine

Creation and Deletion

In order to use Agate in your application, the first step is to create an Agate virtual machine which is represented by a pointer to an AgateVM structure in C. AgateVM is an opaque type. The agateNewVM function gives you a fresh new Agate virtual machine. The agateDeleteVM function deletes the virtual machines and all the associated ressources.

AgateVM *vm = agateNewVM(NULL);

// do something with vm

agateDeleteVM(vm);

Basic Configuration

NULL indicates to use a default configuration for the virtual machine. In many cases, that is not what you want. The AgateConfig structure specifies the configuration of the virtual machine. In this section, we will see some basic configuration settings. Next sections will provide more advanced configuration options. The agateConfigInitialize initializes a configuration structure.

AgateConfig config;
agateConfigInitialize(&config);

// set the configuration

AgateVM *vm = agateNewVM(&config);

// do something with vm

agateDeleteVM(vm);

Assert handling

Agate provides assertions in the language with the assert keyword. The behaviour of a failed assertion is determined by assert_handling in the configuration.

By default, the value of assert_handling is AGATE_ASSERT_ABORT. This means that the script aborts if the assertion fails. This is useful when developping the script. You can also choose that the assertion returns nil instead of stopping the script, with the AGATE_ASSERT_NIL value. In this case, the script may fail later. Or you can also choose that assertions are totally removed from the script with the AGATE_ASSERT_NONE value. This should be the configuration in production, when the script has been well tested.

AgateConfig config;
agateConfigInitialize(&config);
config.assert_handling = AGATE_ASSERT_NONE;

Input/Output

By default, Agate does not print anything, you have to provide functions for this.

The print function is responsible to print a string to the standard output. The simplest implementation of a print function uses the fputs standard function. This function is used by IO.print and related functions.

void print_handler(AgateVM *vm, const char* text) {
  fputs(text, stdout);
}

The write function is responsible to write a single byte to the standard output. It can be used to output binary data to the standard output. The simplest implementation of a write function uses the fputc standard function. This function is used by the IO.write function.

void write_handler(AgateVM *vm, uint8_t byte) {
  fputc(byte, stdout);
}

The error function is responsible to output errors. The function takes the following parameters: the kind of error, the unit name, the line of the error and the error message.

void error_handler(AgateVM *vm, AgateErrorKind kind, const char *unit_name, int line, const char *message) {
  switch (kind) {
    case AGATE_ERROR_COMPILE:
      printf("%s:%d: error: %s\n", unit_name, line, message);
      break;
    case AGATE_ERROR_RUNTIME:
      printf("error: %s\n", message);
      break;
    case AGATE_ERROR_STACKTRACE:
      printf("%s:%d: in %s\n", unit_name, line, message);
      break;
  }
}

The input function is responsible for taking the input from the user. The simplest implementation of an input function uses the fgets standard functions. This function is used by the IO.input function.

void input_handler(AgateVM *vm, char *buffer, size_t size) {
  fgets(buffer, size, stdin);
}

Finally, you can use these functions in the configuration.

AgateConfig config;
agateConfigInitialize(&config);
config.print = print_handler;
config.write = write_handler;
config.error = error_handler;
config.input = print_handler;

Conversions from string

Agate can be configured to use custom integer conversion from string in parse_int and float conversion from string in parse_float. These two functions are used during parsing and in the String.to_i and String.to_f functions.

If set to NULL, a default implementation is provided using strtoll for parse_int and strtod for parse_float, taking care of locale management. If you use Agate in C++17 (or later), you can use std::from_chars which may be faster than the default implementation.

// C++17 implementation of parse_int
bool parse_int(const char *text, ptrdiff_t size, int base, int64_t *result) {
  int64_t value;
  auto [ ptr, ec ] = std::from_chars(text, text + size, value, base);

  if (ec == std::errc()) {
    *result = value;
    return ptr == text + size;
  }

  *result = std::numeric_limits<int64_t>::max();
  return false;
}

// C++17 implementation of parse_float
bool parse_float(const char *text, ptrdiff_t size, double *result) {
  double value;
  auto [ ptr, ec ] = std::from_chars(text, text + size, value, std::chars_format::general);

  if (ec == std::errc()) {
    *result = value;
    return ptr == text + size;
  }

  *result = std::numeric_limits<double>::quiet_NaN();
  return false;
}

Finally, if you really want to override the defaut implementation, you must change the configuration.

AgateConfig config;
agateConfigInitialize(&config);
config.parse_int = parse_int;
config.parse_float = parse_float;

Executing a simple script

After the virtual machine is configured, you can execute a simple script in a string with agateCallString(). The return value indicates if the script was executed without errors (AGATE_STATUS_OK) or if the compilation of the script failed (AGATE_STATUS_COMPILE_ERROR) or if a runtime error occured (AGATE_STATUS_RUNTIME_ERROR).

AgateStatus status = agateCallString(vm, "game", "IO.println(\"Start!\")");

Slots

Slots are identifiers for communicating between the Agate part and the C part. They are indices in an array of values that you can read or write.

Primitive types

Array

Map

Variables

Handles

Handle management

Call handles

Foreign methods

Foreign classes

Calling Agate from C

Advanced configuration

Units