Catspeak Reference


Getting Started

§ Installation

  • Get a recent release of Catspeak from the GitHub releases page. You should see a download for a file with the extension .yymps.

  • Open your project file in the GameMaker IDE.

  • Navigate to the toolbar at the top of the IDE and find "Tools". Click this and select "Import Local Package" from the drop-down menu.

  • Select the .yymps file you downloaded, and follow the wizard to import the Catspeak resources. If you're not sure what to import, click "Add All".

Now you're setup, see the Basic Usage section for some introductory examples, or read through the Introduction section for a full-fat overview.

§ Introduction

Catspeak is the spiritual successor to the old GML function execute_string. This means that custom user code can be executed as a string by your game for modding support or a debug console. In nerdspeak: Catspeak is a compiler backend and virtual machine for executing arbitrary code at runtime.

Unlike execute_string, Catspeak is slightly more involved, requiring three separate steps:

§ Parsing

Parsing is the first step. This involves taking the human-readable form of Catspeak source code, and converting it into an executable form. This can be done from a string or a UTF-8 encoded buffer.

Parsing code from a string using Catspeak.parseString:

var hir = Catspeak.parseString(@'
  let n = 0
  while n <= 10 {
    n += 1
  }
  return "blast off!"
');

Parsing code from a file called "my_mod.meow", using Catspeak.parse:

var file = buffer_load("my_mod.meow");

var hir = Catspeak.parse(file);

buffer_delete(file);

The parser produces a hierarchical intermediate-representation (HIR), storing information like what functions are defined, where they are defined, how many variables are used, what functions are being called and when, etc.

This information is stored as a JSON object, so you can cache this to a file to avoid parsing large mods every time the game loads.

§ Compiling

Compiling is the second step. This involves taking the executable form of a Catspeak program (the HIR obtained from Parsing) and transforms it into a callable GML function.

Compiling a program from the hir using Catspeak.compile:

var program = Catspeak.compile(hir);

§ Executing

Executing is the third and final step; this is the fun part. After compiling a program, it can be called like any ordinary GML function like:

program();

As many times as you want:

program();
program();
program();
repeat (10) {
    program();
}

When adding mod support, you should aim to pre-compile all of your mod scripts at the start of the game, and then reuse the compiled program during gameplay. Otherwise, your game may experience performance issues due to the slowness of parsing and compiling programs relative to execution.

§ Basic Usage

A minimal working example of a function which returns a message is:

// parse Catspeak code
var hir = Catspeak.parseString(@'
  let catspeak = "Catspeak"

  return "hello! from within " + catspeak
');

// compile Catspeak code into a callable GML function
var getMessage = Catspeak.compile(hir);

// call the Catspeak code just like you would any other GML function!
show_message(getMessage());

§ Interfacing with GML

You can expose additional functions, constants, and assets to Catspeak programs by using the methods on Catspeak.interface. For example, using the functions exposeFunction, exposeConstant, and exposeAsset to make show_message, pi, and spr_player available from within a Catspeak function:

Catspeak.interface.exposeFunction("show_message", show_message);
Catspeak.interface.exposeConstant("math_pi", pi);
Catspeak.interface.exposeAsset("sPlayer", spr_player);

Then using these from within a custom Catspeak function, like:

var hir = Catspeak.parseString(@'
  let tau = math_pi * 2;
  show_message([sPlayer, tau]);
');
var program = Catspeak.compile(hir);
program();

This is necessary so that modders are sandboxed from each other, and don't have unchecked access to your entire game state. There are many other ways of exposing GML assets to Catspeak programs, see CatspeakForeignInterface