Lexical Grammar
Statements
Expressions
Standard Library
Library Reference
- Terminal Expressions
- Operator Expressions
Assignment Expressions
- Grouped Expressions
- Array Expressions
- Struct Expressions
- Call Expressions
- Accessor Expressions
- Block Expressions
- If Expressions
- And Expressions
- Or Expressions
Loop Expressions
- Function Expressions
- Continue Expressions
- Break Expressions
- Return Expressions
scr_catspeak_process
Futures Reference
- function catspeak_execute
- function catspeak_compile_buffer
- function catspeak_compile_string
- function catspeak_create_buffer_from_string
- struct CatspeakProcess extends Future
scr_catspeak_config
scr_catspeak_init
scr_catspeak_error
scr_catspeak_vm
scr_catspeak_ir
struct CatspeakFunction
scr_catspeak_intcode
- method setGlobal
- method setGlobalFunction
- method getGlobal
- method existsGlobal
- method getGlobalNames
- method emitBlock
- method emitFunction
- method emitRegister
- method emitPermanentRegister
- method discardRegister
- method emitUnreachable
- method isUnreachable
- method emitConstant
- method emitPermanentConstant
- method emitArgs
- method emitGlobalGet
- method emitGlobalSet
- method emitReturn
- method emitMove
- method emitClone
- method emitCloneTemp
- method emitJump
- method emitJumpFalse
- method emitJumpTrue
- method emitCallSelf
- method emitCall
- method emitSelf
- method emitCode
- method emitCodeHoisted
- method emitGet
- method emitSet
- method lastCode
- method lastCodeHoisted
- method patchInst
- method patchInstReturn
- method patchArg
- method patchPermanentRegisters
- method toString
- method disassembly
- struct CatspeakBlock
- struct CatspeakAccessor
- struct CatspeakReadOnlyAccessor extends CatspeakAccessor
- struct CatspeakTempRegisterAccessor extends CatspeakAccessor
- enum CatspeakIntcode
- function catspeak_intcode_show
- function catspeak_intcode_read
- function catspeak_intcode_valueof
- function catspeak_intcode_sizeof
scr_catspeak_compiler
struct CatspeakCompiler
scr_catspeak_lexer
- method advance
- method matches
- method satisfies
- method consume
- method consumeLinebreaks
- method error
- method errorAndAdvance
- method expects
- method expectsSemicolon
- method declareLocal
- method getVar
- method pushState
- method pushResult
- method topResult
- method popResult
- method pushBlock
- method popBlock
- method pushIt
- method topIt
- method popIt
- method pushLoop
- method topLoop
- method popLoop
- method inProgress
- method emitProgram
- struct CatspeakLocalScope
- struct CatspeakGlobalAccessor
- struct CatspeakCollectionAccessor
struct CatspeakLexer
scr_catspeak_token
- method registerByte
- method registerLexeme
- method clearLexeme
- method advance
- method peek
- method advanceWhile
- method nextWithWhitespace
- method next
- function catspeak_token_is_operator
- function catspeak_token_is_expression
- function catspeak_token_skips_newline
- function catspeak_string_to_token_keyword
- function catspeak_byte_to_token
- enum CatspeakToken
- function catspeak_token_show
- function catspeak_token_read
- function catspeak_token_valueof
- function catspeak_token_sizeof
scr_catspeak_alloc
scr_future
- Theory
- License
================================================================================
Installation (link) .txt
================================================================================
- enum FutureState
struct Future
scr_future_file
- method accept
- method reject
- method resolved
- method andThen
- method andCatch
- method andFinally
- function future_all
- function future_any
- function future_settled
- function future_ok
- function future_error
- function is_future 1) Get a recent release of Catspeak from the [GitHub releases page].
You should see a download for a file with the extension `
================================================================================
Disclaimer (link) .txt
================================================================================
.yymps
`.
2) Open your project file in the GameMaker IDE.
3) 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.
4) 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 the [Configuration] section for details about what can be customised within
the Catspeak engine.Catspeak is currently a solo project (by [katsaii]), and is being maintained in
my free-time. However, if you want to make a suggestion or report a bug, please
do report it on [GitHub] and I will try to review it as soon as possible!
================================================================================
Features (link) .txt
================================================================================
- **Minimal setup required** ...
ready to use after installation. No need to call any weird "init" or
"update" functions. (Unless you want to, as a treat!)
- **Cross-platform** ...
allowing mods to work on any platform out of the box. Tried and tested on
the VM and YYC exports on windows, as well as HTML5.
- **Sandboxed execution environment** ...
so modders cannot modify the sensitive parts of your game you don't want
them to.
- **Customisable standard library** ...
exposing only the functions you want modders to have access to. See the
section on [Customising the Standard Library] for more information and
examples.
- **Performant runtime** ...
capable of interpreting thousands of (and even tens of thousands of)
Catspeak scripts per step. (Dependent on the complexity of your scripts.)
- **Asynchronous execution over multiple steps** ...
making it impossible for modders to freeze your game with infinite loops.
- **Intelligent process manager** ...
so no time is wasted idly waiting for new Catspeak programs to appear.
- **Failsafes to catch unresponsive Catspeak processes**.
Customise how this is done through the [catspeak_config] function.
- **Call GML code from Catspeak**.
Just use the syntax you're familiar with: `
================================================================================
Configuration (link) .txt
================================================================================
is_string(value)
`. See more
in the [Syntax] section.
- **Call Catspeak code from GML** ...
using the [catspeak_execute] function. See [Basic Usage] for some
examples.
- **Simple, relaxed syntax** ...
but still similar enough to GML to be familiar.
- **Pre-compilation of scripts** ...
to both reduce load times when initialising mods or obfuscate production
code. (Coming Soon!)
- **Compiler internals exposed and well-documented** ...
in order to give power users as much control over their programs as
possible. (See the [Library Reference].)
- **Cute name and mascot**.The primary method of configuring Catspeak is through the [catspeak_config]
function. This function exposes a struct containing all the global settings,
such as how long processes are allowed to run before they become
unresponsive.
**Please read** the documentation for [catspeak_config] to get an in-depth
description of what each option does.
Below are a couple of examples showing how to read/write configurations:
```
================================================================================
Basic Usage (link) .txt
================================================================================
var configs = catspeak_config();
configs.frameAllocation = 0.25; // only run Catspeak for 25% of a frame
configs.processTimeLimit = 5; // all processes can run for 5 seconds
// before being forced to stop
// get the current process time limit
var timeLimit = configs.processTimeLimit;
```In Catspeak, Compiling and running programs are separate steps. You should aim
to perform any compilation of scripts during a loading screen so that running
your programs is much faster.
Compiling Programs (link) .txt
==============================================================================
The first step to running your Catspeak programs involves compiling the
source code from its human-readable form into an executable form. This can be
done in two ways: from a GML string, or from a character buffer.
Compiling From A String (link) .txt
----------------------------------------------------------------------------
If your Catspeak program is stored within a GML string, you can use the
[catspeak_compile_string] function to compile it. Consider the following
program:
```
Compiling From A Buffer (link) .txt
----------------------------------------------------------------------------
// counts to 10 and then returns a message
var src = @'
let n = 0
while (n <= 10) {
print n
n = it + 1
}
return "blast off!"
';
```
You can use the [catspeak_compile_string] function to asynchronously compile
the sourc code:
```
var process = catspeak_compile_string(src);
```
The `process
` variable stores a reference to a [CatspeakProcess] responsible
for compiling your code. Once the process is complete, you can retreive the
result using the [andThen] method:
```
process.andThen(function(code) {
show_message("success!");
});
```
If the program fails to compile, this callback function will never execute.
In this case, you will need to use the `andCatch
` method to catch the
compilation error:
```
process.andCatch(function(err) {
show_message("oh no, an error occurred!");
});
```
For more information on this behaviour, see the [Future] definition.
If after running this example you see a pop-up window with the message
"success!", then **congratulations!** You have successfully compiled your
first Catspeak program. For information on how to run this program, see the
[Executing Programs] section. Compiling a buffer works similarly to [Compiling From a String], except you
use the [catspeak_compile_buffer] function:
```
Executing Programs (link) .txt
==============================================================================
catspeak_compile_buffer(buff).andThen(function(code) {
show_message(code.disassembly());
});
```
Different from the [catspeak_compile_string] function, the buffer version
accepts an additional parameter, that if set to `true
` will automatically
delete the buffer once the compiler process ends so you don't have to. By
default, this is set to `false
`. The second step to running your Catspeak programs is to interpret the
compiled code. This can be done using the `
Customising The Standard Library (link) .txt
==============================================================================
catspeak_execute
` function.
Following on from the example shown in [Compiling From a String], the
function contained in the `code
` variable can be interpreted like so:
```
catspeak_execute(code).andThen(function(result) {
show_message(result);
});
```
This will spawn a new [CatspeakProcess] which goes through the process of
interpreting the compiled code. Once the program has finished running, the
callback to the [andThen] method is called with the result of the program. In
this example, the result was the string `"blast off!"
`, so a pop-up window
with the message "blast off!" will be shown.
If everything went to plan, you should have just compiled and executed your
first Catspeak program!
NOTE: If you do not care about the result of the program, you can omit the
[andThen] method call. You can expose additional functions and constants to Catspeak programs by
using [catspeak_add_function] and [catspeak_add_constant]. For example,
adding a new function to display a "hello" message in a pop-up window:
```
================================================================================
Syntax (link) .txt
================================================================================
catspeak_add_function("say_hello", function() {
show_message("hello");
});
```
From now on, any Catspeak **new** programs will be able to use the `say_hello
`
function.Catspeak is a simple imperative language with a vaguely similar syntax to GML.
As an example, consider the following program written in GML to calculate the
factorial of a number `
Lexical Grammar (link) .txt
==============================================================================
n
`:
```
// GML CODE
function factorial(n) {
var m = 1;
if (n > 1) {
m = n * factorial(n - 1);
}
return m;
}
factorial(5); // output: 120
```
NOTE: This example is intentionally verbose in order to showcase: variables,
function declarations, identifiers, "if" statements, function calls,
assignment statements, return statements, and comments.
Below is the same program written in Catspeak:
```
-- CATSPEAK CODE
factorial = fun(n) {
let m = 1
if (n > 1) {
m = n * factorial(n - 1)
}
return m
}
factorial(5) -- output: 120
```
There are some immediately obvious differences here, such as the `m
` variable
being declared using `let
` instead of `var
`, `fun
` instead of `function
`, and
comments using `--
` instead of `//
`. All of these differences (and more) are
described in the [Lexical Grammar] section. Catspeak source code is a sequence of ASCII characters. This unfortunately
means that Unicode support is not guaranteed to work, but results in a faster
compiler.
This sequence of characters first needs to be transformed into larger groups
of characters called "tokens". The following sections will cover what each
of these tokens are composed of.
Whitespace (link) .txt
----------------------------------------------------------------------------
For the most part, Catspeak is whitespace insensitive. There are exceptions
to this for [Identifiers] and [Automatic Semicolon Insertion], but otherwise
Catspeak ignores the following characters:
- Character tabulation '\t' (code point U+0009)
- Line feed '\n' (code point U+000A)
- Line tabulation '\v' (code point U+000B)
- Form feed '\f' (code point U+000C)
- Carriage return '\r' (code point U+000D)
- Space (code point U+0020)
- Next Line (code point U+0085)
Comments (link) .txt
----------------------------------------------------------------------------
The only way to add a comment in Catspeak is to use the special `
Identifiers (link) .txt
----------------------------------------------------------------------------
--
` symbol.
This will ignore all of the characters after it until a new line is reached.
For example:
```
-- this is a Catspeak comment!
```
NOTE: Unlike GML, Catspeak does not support multi-line comments.
Use multiple comments instead.
NOTE: Because Catspeak allows for custom operators, you **must only** use
`--
` and not something like `---
` or `--//
`; otherwise it will be
considered a custom operator identifier. For more information, see the
[Operator Identifiers] section. Identifiers are mainly used for variable names in Catspeak. The most common
kind of identifier is the alphanumeric identifier. These identifiers start
with a letter and are followed by a sequence of other letters, numbers,
underscores (_), or apostrophes (').
An example of an identifier which uses all of these is `
Raw Identifiers (link) .txt
--------------------------------------------------------------------------
Can't_count_to_10
`.
The following identifiers are invalid:
```
_invalid
1Invalid
'INVALID'
``` Raw identifiers are a special type of identifier which starts and ends
with the backtick symbol:
```
Operator Identifiers (link) .txt
--------------------------------------------------------------------------
let
`1st-of-march` = "2022-03-01"
```
You can use any valid identifier character between the backticks, in
whatever order you decide. This includes [Operator Identifiers]. Operators in Catspeak aren't special, they are just a kind of identifier
which use symbols instead of letters or numbers. Below is a list of valid
characters which can be used as operators, sorted by highest precedence
to lowest precedence.
highest precedence (7): `
Keywords (link) .txt
----------------------------------------------------------------------------
#
`, `.
`, `@
`
(6): `%
`, `\
`
. (5): `*
`, `/
`
. (4): `+
`, `-
`
. (3): `!
`, `<
`, `=
`, `>
`, `?
`, `~
`
. (2): `&
`
(1): `^
`, `|
`
lowest precedence (0): `$
`, `:
`, `;
`
Operators on the same line share the same precedence.
You can combine as many, or as few, of these symbols together to create
your very own operator. Here are a few: `>>=
`, `><>
`, `;~;
`, `>*^-^*<
`.
The precedence of the new operator will be the same as its first
character. So the `>>=
` operator will have the same precedence as `>=
`. Catspeak reserves the following identifiers as keywords:
- `
Literals (link) .txt
----------------------------------------------------------------------------
Numeric Literals (link) .txt
--------------------------------------------------------------------------
--
` see [Comments]
- `=
` see [Let Statements] and [Assignment Expressions]
- `:
` see [Struct Expressions]
- `;
` see [Automatic Semicolon Insertion]
- `.
` see [Accessor Expressions]
- `...
` see [Automatic Semicolon Insertion]
- `do
` see [Block Expressions]
- `if
` see [If Expressions]
- `else
` see [If Expressions]
- `while
` see [While Expressions]
- `for
` (reserved in case of `for
` loops)
- `loop
` (reserved in case of infinite loops)
- `let
` see [Let Statements]
- `fun
` see [Function Expressions]
- `break
` see [Break Expressions]
- `continue
` see [Continue Expressions]
- `return
` see [Return Expressions]
- `impl
` (reserved in case of constructor functions)
- `new
` (reserved in case of constructor functions)
- `self
` (reserved in case of method binding)
- `and
` (reserved in case of short-circuit AND)
- `or
` (reserved in case of short-circuit OR) Numeric literals are a sequence of ASCII digits, optionally separated by
a single decimal point:
```
String Literals (link) .txt
--------------------------------------------------------------------------
1234567890
3.1415
``` There are two types of string literal in Catspeak. The most common is
a sequence of characters starting and ending in double quotes ("):
```
Automatic Semicolon Insertion (link) .txt
----------------------------------------------------------------------------
let hi = "hello world"
```
This type of string allows the following escape sequences to be used:
- \" Quotation mark
- \ Escape new line
- \\ Backslash
- \t Character tabulation
- \n Line feed
- \v Line tabulation
- \f Form feed
- \r Carriage return
The other type of string is the **raw string**. A raw string is prefixed
by the `@
` character, and does not interpret any of the previously
mentioned escape sequences:
```
let hi_again = @"\hello\"
``` Automatic semicolon insertion is a process used to help Catspeak understand
when a statement has ended so that another can begin. A semicolon or new
line will be expected after the [Let Statement] and [Expression Statement].
All new lines are considered semicolons unless it is preceeded by the
`
Statements (link) .txt
==============================================================================
...
` operator, or one of the following tokens:
- Parens: `(
`, `[
`, `{
`
- Built-in operators: `.
`, `:
`, `,
`, `=
`
- Keywords: `do
`, `if
`, `else
`, `while
`, `for
`, `let
`, `fun
`
- User-defined operators, see [Operator Identifiers]
This means that in order to write Catspeak code in the Allman style, you
must use `...
` to tell Catspeak that you are continuing the line:
```
while (x == y) ...
{
something()
}
```
This is not necessary for styles where the first `{
` appears on the same
line:
```
while (x == y) {
something()
}
```
NOTE: Although none of the examples in this document will use them, you
can add explicit semicolons after each of your statements if you
prefer. Unlike GML, Catspeak only has two kinds of statement: [Let Statements] and
[Expression Statements]. This is because Catspeak is an expression-oriented
language, so things like "if" statements become [If Expressions].
Let Statements (link) .txt
----------------------------------------------------------------------------
The `
Expression Statements (link) .txt
----------------------------------------------------------------------------
let
` statement creates a new local variable in the current block
scope. It can optionally be followed by an initialiser expression. If no
initialiser expression is used, then the variable will be initialised to
`undefined
`:
```
let a = 1 + 3 -- initialised to the value 3
let b -- initialised to undefined
```
Unlike GML, catspeak variables are no longer visible after the end of their
enclosing block scope, unless another variable of the same name exists in
an outer scope. Most often, an expression statement will evaluate its expression and ignore
the result. There is an exception to this rule with [Do Expressions].
Expressions (link) .txt
==============================================================================
An expression is is a term which always produces a value, and may be
composed of many sub-expressions. All statements you would typically find
in GML appear as expressions in Catspeak. This includes [Break Expressions],
[Return Expressions], and [Continue Expressions], all of which return the
**never** type; indicating that the expression never returns.
Terminal Expressions (link) .txt
----------------------------------------------------------------------------
Terminal expressions are either non-operator [Identifiers] or [Literals].
These expressions have no further sub-expressions, hence the name.
Operator Expressions (link) .txt
----------------------------------------------------------------------------
Operator expressions can either be unary or binary. A unary operator
expression is an operator identifier followed by an [Accessor Expression],
[Terminal Expression], or [Grouped Expression]:
```
Assignment Expressions (link) .txt
----------------------------------------------------------------------------
let unary = -2;
```
A binary operator is made up of an operator identifier sandwiched between
two expressions:
```
let binary = 0.1 + 0.9
```
Both unary and operator expressions are sugar for [Call Expressions]:
```
let unary =
`-`(2)
let binary =
`+`(0.1, 0.9)
``` Assignment expressions are made up of two sub-expressions separated by
the `
It Expressions (link) .txt
--------------------------------------------------------------------------
=
` symbol. The value of the right-hand-side expression will be
assigned to the memory location pointed to by the left-hand-side
expression.
NOTE: The value of an assignment expression will be the value assigned
to the variable on the left-hand-side of the expression:
```
let a
let b = a = 1
print a == b -- outputs: true
``` Catspeak does not have reference types. Because of this, it cannot support
typical incrementation operators such as `
Grouped Expressions (link) .txt
----------------------------------------------------------------------------
+=
`. To solve this problem,
Catspeak has an `it
` keyword:
```
x = it + 1 -- behaves like x += 1 would in GML
```
The value of the `it
` expression will be the value of the left-hand-side
sub-expression of its containing assignment expression. So, in the above
example, the value of `it
` will be the value of the `x
` variable.
The nice thing about this syntax is it generalises to any expression or
function call:
```
x = update(it)
```
This becomes noticable useful when handling [Accessor Expressions]:
```
arr.[0] = update(it)
```
instead of
```
arr.[0] = update(arr.[0])
``` A grouped expression wraps a single sub-expression between `
Array Expressions (link) .txt
----------------------------------------------------------------------------
(
` and `)
`,
evaluating the sub-expression. This is typically used to make the
precedence of the inner expression clear:
```
let a = 1 + 2 * 3 -- 7
let b = (1 + 2) * 3 -- 9
``` Arrays are a sequence of comma-separated sub-expressions wrapped between
`
Struct Expressions (link) .txt
----------------------------------------------------------------------------
[
` and `]
`:
```
let array = [1, 2, 3]
```
For information on how to modify array values see [Accessor Expressions]. Structs are a sequence of comma-separated key-value pairs wrapped between
`
Call Expressions (link) .txt
----------------------------------------------------------------------------
{
` and `}
`:
```
let struct = { x: 1, y: 2 }
```
Typically, the key-value pairs are separated by a single `:
`. However,
there is a short-hand syntax for when the key and value use the same
identifier:
```
{ a, b, c }
```
is short for
```
{ a: a, b: b, c: c }
```
Typically, the key for a struct element must be a [Terminal Expression];
these are either [Identifiers] or [Literals]. However, using an
expression for the key value is allowed, so long as the expression is
between `[
` and `]
`:
```
{ ["hello" ++ "world"]: 123 }
```
For information on how to modify struct values see [Accessor Expressions]. A call expression calls a function with a set of arguments. The call syntax
in Catspeak is a lot less restrictive than GML, allowing parenthesis on the
arguments to be optional. This allows for the creation of statement-like
function calls, like the `
Accessor Expressions (link) .txt
----------------------------------------------------------------------------
print
` function found in the [Standard Library]:
```
print("hello", "world")
-- this is also valid:
print "hello", "world"
``` An accessor expression will allow you to access the elements of an array
or struct. They consist of two expressions separated by a `
Block Expressions (link) .txt
----------------------------------------------------------------------------
.
` symbol.
The right-hand-side expression must be a [Terminal Expression], **or**
an expression wrapped between `[
` and `]
`:
```
array.[0]
struct.x
struct.["y"]
```
NOTE: The `struct.x
` syntax is short-hand for `struct.["x"]
`.
Depending on which side of an [Assignment Expression] the accessor
expression is on, determines whether an element will be "get" or "set". The block expression is used to execute multiple statements or control
flow expressions before returning a final result. Create a block
expression by using the `
If Expressions (link) .txt
----------------------------------------------------------------------------
do
` keyword, following by a sequence of
[Statements] wrapped between `{
` and `}
`:
```
let a = do {
let a = 1
let b = 2
a + b
}
```
The result returned by the block expression will be the result of the
last expression in the block. If there is no expression, then the result
will be `undefined
`.
Reiterating what was said in the [Let Statements] section, all local
variables defined within a block expression will become inaccessible after
the block has ended. This is different from GML variables, whose
definitions are hoisted. The syntax for `
And Expressions (link) .txt
----------------------------------------------------------------------------
if
` expressions is similar to GML `if
` statements:
```
if (a > b) {
-- a is greater than b
} else {
-- a is not greater than b
}
```
Just like GML, the `else
` clause is optional.
However, unlike GML, only an `if
` expression can be used after an `else
`
clause. So shortcuts `else while
` or `else do
` are not allowed. Similar to GML, Catspeak has native `
Or Expressions (link) .txt
----------------------------------------------------------------------------
and
` operators:
```
a and b
```
In this example, if the expression `a
` evaluates to `true
`, then the
result of the expression is the value of `b
`. Otherwise, the value of `a
`
is used.
NOTE: If `a
` is false, the value of `b
` is **never calculated**. Similar to GML, Catspeak has native `
Loop Expressions (link) .txt
----------------------------------------------------------------------------
While Expressions (link) .txt
--------------------------------------------------------------------------
or
` operators:
```
a or b
```
In this example, if the expression `a
` evaluates to `false
`, then the
result of the expression is the value of `b
`. Otherwise, the value of `a
`
is used.
NOTE: If `a
` is true, the value of `b
` is **never calculated**. The `
Function Expressions (link) .txt
----------------------------------------------------------------------------
while
` expression resembles [If Expressions], except the `while
`
keyword is used instead of `if
`:
```
while (a > b) {
a = it - 1
}
```
Unlike [If Expressions], the `while
` expression will continue to repeat
the code between the `{
` and `}
` until the condition evaluates to
`false
`.
Use [Break Expressions] or [Continue Expressions] to exit the loop or
skip to the next iteration early. Catspeak lets you define new functions using the `
Continue Expressions (link) .txt
----------------------------------------------------------------------------
fun
` keyword, followed
by a block of code to execute:
```
let say_hello = fun() {
print "Hello!"
}
```
To create a function which accepts arguments, include the names of the
arguments after the `fun
` keyword:
```
let add = fun(a, b) {
return a + b
}
```
Just like [Call Expressions], the parenthesis around these arguments are
optional:
```
let add = fun a, b {
return a + b
}
```
NOTE: All functions in Catspeak are anonymous. The `
Break Expressions (link) .txt
----------------------------------------------------------------------------
continue
` expression will immediately jump to the start of the current
loop body, entering the next iteration of the loop if one exists. The `
Return Expressions (link) .txt
----------------------------------------------------------------------------
break
` expression will immediately jump to the end of the current
loop body:
```
let n = 0
while (n < 100) {
n = n + 1
if (n > 10) {
break
}
}
print n -- outputs: 11
``` The `
================================================================================
Standard Library (link) .txt
================================================================================
return
` expression will immediately terminate the current function
call and returns its argument as its result. If no argument is given,
`undefined
` is used as the result instead.
```
let max = fun(a, b) {
if (a > b) {
return a
}
return b
}
```Catspeak has a small standard library which contains common constants and
functions that are considered necessary for all programs. If you have any
suggestions on what could be added to this standard library, please submit
them to the [GitHub] page.
Constants (link) .txt
==============================================================================
Catspeak shares all the primitive constants of GML, these are:
- `
Functions (link) .txt
==============================================================================
undefined
`
- `true
`
- `false
`
- `NaN
`
- `infinity
`
However, instead of `pointer_null
` Catspeak uses just `null
`. This is in
order to maintain compatibility with JSON. Catspeak exposes the following GML functions for checking the types of
values and performing conversions:
- `
Operators (link) .txt
==============================================================================
bool
` - `is_array
` - `is_nan
` - `is_undefined
`
- `string
` - `is_bool
` - `is_numeric
` - `is_vec3
`
- `real
` - `is_infinity
` - `is_ptr
` - `is_vec4
`
- `int64
` - `is_int32
` - `is_real
`
- `typeof
` - `is_int64
` - `is_string
`
- `instanceof
` - `is_method
` - `is_struct
`
In addition to these functions, there are two Catspeak-specific functions:
- `print
` takes a variable number of values and prints them to the console
window. Internally this behaves like `show_debug_message
`.
- `len
` returns the number of items in a GML array or struct. Catspeak shares many operators with GML, but there are some differences.
Listed below are the default operators defined by Catspeak. You can find
their precedences in the section on [Operator Identifiers].
- `
================================================================================
Library Reference (link) .md
================================================================================
.
` field accessor - `<
` less-than
- `%
` remainder - `<=
` inclusive less-than
- `*
` multiplication - `!
` logical negation
- `/
` division - `~
` bitwise negation
- `//
` integer division - `>>
` bitwise right-shift
- `-
` subtraction, negation - `<<
` bitwise left-shift
- `+
` addition - `&&
` logical **AND**
- `++
` string addition - `&
` bitwise **AND**
- `==
` equals - `^^
` logical **XOR**
- `!=
` not-equals - `^
` bitwise **XOR**
- `>
` greater-than - `||
` logical **OR**
- `>=
` inclusive greater-than - `|
` bitwise **OR**
NOTE: All operators are left-associative in Catspeak.
NOTE: Unlike GML, the operators `&&
` and `||
` are **not short-circuiting**.
This means that both the left and right hand-side of the operator will
be evaluated immediately. If you need this behaviour, you should use
[And Expressions] and [Or Expressions].
Catspeak does not have `xor
`, `mod
` and `div
` operators. You will need to
use `^^
`, `%
`, and `//
` instead.The following sections feature documentation for all public Catspeak functions,
macros, and structs.
scr_catspeak_process (link) .gml
==============================================================================
The primary user-facing interface for compiling and executing Catspeak
programs.
function catspeak_execute (link) .gml
----------------------------------------------------------------------------
Creates a new Catspeak runtime process for this Catspeak function. This
function is also compatible with GML functions.
@param
function catspeak_compile_buffer (link) .gml
----------------------------------------------------------------------------
scr
: Function | Struct.CatspeakFunction
The GML or Catspeak function to execute.
@param (optional) args
: Array<Any>
The array of arguments to pass to the function call. Defaults to the
empty array.
@returns a value of Struct.CatspeakProcess Creates a new Catspeak compiler process for a buffer containing Catspeak
code.
@param
function catspeak_compile_string (link) .gml
----------------------------------------------------------------------------
buff
: ID.Buffer
A reference to the buffer containing the source code to compile.
@param (optional) consume
: Bool
Whether the buffer should be deleted after the compiler process is
complete. Defaults to `false
`.
@param (optional) offset
: Real
The offset in the buffer to start parsing from. Defaults to 0, the
start of the buffer.
@param (optional) size
: Real
The length of the buffer input. Any characters beyond this limit will
be treated as the end of the file. Defaults to `infinity
`.
@returns a value of Struct.CatspeakProcess Creates a new Catspeak compiler process for a string containing Catspeak
code. This will allocate a new buffer to store the string, if that isn't
ideal then you will have to create and write to your own buffer, then
pass it into the [catspeak_compile_buffer] function instead.
@param
function catspeak_create_buffer_from_string (link) .gml
----------------------------------------------------------------------------
src
: Any
The value containing the source code to compile.
@returns a value of Struct.CatspeakProcess A helper function for creating a buffer from a string.
@param
struct CatspeakProcess extends Future (link) .gml
----------------------------------------------------------------------------
src
: String
The source code to convert into a buffer.
@returns a value of Id.Buffer Constructs a new asynchronous Catspeak process. Instances of this struct
will be managed globally by the Catspeak execution engine. Execution time
is divided between all active processes so each gets a chance to progress.
@param
scr_catspeak_config (link) .gml
==============================================================================
resolver
: Function
A function which performs the necessary operations to progress the state
of this future. It accepts a single function as a parameter. Call this
function with the result of the future to complete the computation. The primary user-facing interface for configuring the Catspeak execution
engine.
Many parts of the Catspeak engine expose configuration features. These
are:
- "frameAllocation" should be a number in the range [0, 1]. Determines
what percentage of a game frame should be reserved for processing
Catspeak programs. Catspeak will only spend this time when necessary,
and will not sit idly wasting time. A value of 1 will cause Catspeak
to spend the whole frame processing, and a value of 0 will cause
Catspeak to only process a single instruction per frame. The default
setting is 0.5 (50% of a frame). This leaves enough time for the other
components of your game to complete, whilst also letting Catspeak be
speedy.
- "processTimeLimit" should be a number greater than 0. Determines how
long (in seconds) a process can run for before it is assumed
unresponsive and terminated. The default value is 1 second. Setting
this to `
function catspeak_config (link) .gml
----------------------------------------------------------------------------
infinity
` is technically possible, but will not be officially
supported.
- "keywords" is a struct whose keys map to [CatspeakToken] values.
This struct can be modified to customise the keywords expected by the
Catspeak compiler. For example, if you would like to use "func" for
functions (instead of the default "fun"), you can add a new definition:
```
var keywords = catspeak_config().keywords;
keywords[$ "func"] = CatspeakToken.FUN;
variable_struct_remove(keywords, "fun"); // delete the old keyword
```
Please take care when modifying this struct because any changes will
be **permanent** until you close and re-open the game. Configures various global settings of the Catspeak compiler and runtime.
See the list in [scr_catspeak_config] for configuration values and their
usages.
@returns a value of Struct
function catspeak_add_function (link) .gml
----------------------------------------------------------------------------
Permanently adds a new Catspeak function to the default standard library.
@param
function catspeak_add_constant (link) .gml
----------------------------------------------------------------------------
name
: String
The name of the function to add.
@param f
: Function
The function to add, will be converted into a method if a script ID
is used.
@param ...
: Any
The remaining key-value pairs to add, in the same pattern as the two
previous arguments. Permanently adds a new Catspeak constant to the default standard library.
If you want to add a function, use the [catspeak_add_function] function
instead because it makes sure your value will be callable from within
Catspeak.
@param
scr_catspeak_init (link) .gml
==============================================================================
name
: String
The name of the constant to add.
@param value
: Any
The value to add.
@param ...
: Any
The remaining key-value pairs to add, in the same pattern as the two
previous arguments. Initialises core components of the Catspeak compiler. This includes
any uninitialised global variables.
macro CATSPEAK_VERSION (link) .gml
----------------------------------------------------------------------------
The compiler version, should be updated before each release.
function catspeak_force_init (link) .gml
----------------------------------------------------------------------------
Makes sure that all Catspeak global variables are initialised. Only needs
to be called if you are trying to use Catspeak from a script, or through
`
scr_catspeak_error (link) .gml
==============================================================================
gml_pragma
`. Otherwise you can just ignore this. Responsible for the creation and manipulation of Catspeak errors raised
by the compiler and runtime environment. Actual error information is
located in instances of the [CatspeakError] struct. This struct may also
contain debug information, located in instances of [CatspeakLocation].
struct CatspeakLocation (link) .gml
----------------------------------------------------------------------------
Represents a line and column number in a Catspeak source file.
@param
method clone (link) .gml
--------------------------------------------------------------------------
line
: Real
The line number this position is found on.
@param (optional) column
: Real
The column number this position is found on. This is the number of
characters since the previous new-line character; therefore, tabs are
considered a single column, not 2, 4, 8, etc. columns. Returns an exact copy of this debug information.
@returns a value of Struct.CatspeakLocation
@example
```
method reflect (link) .gml
--------------------------------------------------------------------------
var a = new CatspeakLocation(10, 20);
var b = a.clone();
``` Copies values from this location to a new [CatspeakLocation] without
creating a new instance.
@deprecated This function is deprecated and its usage is discouraged!
Use [assign] instead.
@param
method assign (link) .gml
--------------------------------------------------------------------------
source
: Struct.CatspeakLocation
The target location to sample from. Assigns the values of another instance of [CatspeakLocation] to this
instance.
@param
method toString (link) .gml
--------------------------------------------------------------------------
source
: Struct.CatspeakLocation
The target location to sample from.
@example
```
var a = new CatspeakLocation(10, 20);
var b = new CatspeakLocation(-1);
b.assign(a); // copies the line and column values from
`a` to
`b`
``` Renders this Catspeak location. If a line number and column number
both exist, then the format will be `
struct CatspeakError (link) .gml
----------------------------------------------------------------------------
(line N, column M)
`. Otherwise,
if only a line number exists, the format will be `(line N)
`.
If this source location also includes a debug text, it is also included
in the debug output between square brackets.
@returns a value of String
@example
```
show_message(new CatspeakLocation(20)); // (line 20)
show_message(new CatspeakLocation(20, 16)); // (line 20, column 16)
``` Represents an error raised by the Catspeak runtime. Follows a similar
structure to the built-in error struct.
@param
method toString (link) .gml
--------------------------------------------------------------------------
location
: Struct.CatspeakLocation
The location where this error occurred.
@param (optional) message
: String
The error message to display. Defaults to "No message". Renders this Catspeak error with its location followed by the error
message.
@param (optional)
function catspeak_assert (link) .gml
----------------------------------------------------------------------------
verbose
: Bool
Whether to include the stack trace as part of the error output.
@returns a value of String Raises a Catspeak error at this location, with this message, if an
assertion condition is not true.
@param
scr_catspeak_vm (link) .gml
==============================================================================
condition
: Bool
The condition to check. Use `false
` to raise an exception.
@param pos
: Struct.CatspeakLocation
The location where this error occurred.
@param (optional) message
: String
The error message to display. Handles the code execution stage of the Catspeak runtime.
struct CatspeakVM (link) .gml
----------------------------------------------------------------------------
Creates a new Catspeak virtual machine, responsible for the execution
of Catspeak IR.
method pushCallFrame (link) .gml
--------------------------------------------------------------------------
Creates a new executable callframe for this IR.
@param
method reuseCallFrame (link) .gml
--------------------------------------------------------------------------
self_
: Struct
The "self" scope to use when calling this function.
@param ir
: Struct.CatspeakFunction
The Catspeak IR to execute. The VM is pretty stupid, so if the code is
not well-formed, there are likely to be runtime errors and misbehaviour.
@param (optional) args
: Array<Any>
The arguments to pass to this VM call.
@param (optional) argo
: Real
The offset in the arguments array to start at.
@param (optional) argc
: Real
The number of arguments in the arguments array. An unsafe function which can be used as a shortcut if you are going
to reuse the previous callframe with the same settings. There are no
checks that a valid callframe even exists, so keep that in mind.
method reuseCallFrameWithArgs (link) .gml
--------------------------------------------------------------------------
An unsafe function similar to [reuseCallFrame], except a new set of
arguments can be passed into the frame.
@param
method popCallFrame (link) .gml
--------------------------------------------------------------------------
args
: Array<Any>
The arguments to pass to this VM call.
@param (optional) argo
: Real
The offset in the arguments array to start at.
@param (optional) argc
: Real
The number of arguments in the arguments array. Removes the top callframe from the stack.
method inProgress (link) .gml
--------------------------------------------------------------------------
Returns whether the VM is in progress.
method runProgram (link) .gml
--------------------------------------------------------------------------
Performs a `
scr_catspeak_ir (link) .gml
==============================================================================
n
`-many steps of the execution process. Just like the
compiler, these steps try to be discrete so that the VM can be paused
if necessary. However, this does not account for external code that
may perform large amounts of processing, such as a GML function
containing a computationally expensive loop.
@param n
: Real
The number of steps of process. Handles the flat, executable representation of Catspeak programs.
struct CatspeakFunction (link) .gml
----------------------------------------------------------------------------
Represents the executable Catspeak VM code. Also exposes methods for
constructing custom IR manually.
@param (optional)
method setGlobal (link) .gml
--------------------------------------------------------------------------
name
: String
The name to give this function, defaults to "main".
@param (optional) parent
: Struct.CatspeakFunction
The function this new function was defined in. Inherits its global
variables. Sets the value of a global variable with this name.
@param
method setGlobalFunction (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the global variable to set.
@param value
: Any
The value to assign to this global variable. Behaves similarly to [setGlobal], except if the value is not a method
it is converted into a method type.
@param
method getGlobal (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the global variable to set.
@param value
: Any
The value to assign to this global variable. Gets the value of a global variable with this name.
@param
method existsGlobal (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the global variable to get.
@returns a value of Any Returns whether a global variable exists with this name.
@param
method getGlobalNames (link) .gml
--------------------------------------------------------------------------
method emitBlock (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the global variable to get.
@returns a value of Bool Adds a Catspeak block to the end of this function.
@param
method emitFunction (link) .gml
--------------------------------------------------------------------------
block
: Struct.CatspeakBlock
The Catspeak block to insert.
@returns a value of Struct.CatspeakBlock Creates a new sub-function and returns its reference.
@param (optional)
method emitRegister (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the sub-function.
@returns a value of Struct.CatspeakFunction Allocates space for a new Catspeak register. This just returns the
id of the register, since there is no "physical" representation.
@param (optional)
method emitPermanentRegister (link) .gml
--------------------------------------------------------------------------
pos
: Struct.CatspeakLocation
The debug info for this register.
@returns a value of Real Returns the next persistent register ID. Persistent registers are not
allocated immediately, they hold a temporary ID until the rest of the
code is generated. Once this is complete, these special registers are
allocated at the end of the register list. This is done in order to
avoid messing up CALLSPAN instruction optimisations, where arguments are
expected to be adjacent.
@param (optional)
method discardRegister (link) .gml
--------------------------------------------------------------------------
pos
: Struct.CatspeakLocation
The debug info for this register.
@returns a value of Real Discards a register so it can be recycled somewhere else.
@param
method emitUnreachable (link) .gml
--------------------------------------------------------------------------
reg
: Any
The register or accessor to check. Emits the special unreachable "register." The existence of this
flag will make dead code elimination easier in an optimisation phase.
@returns a value of Real
method isUnreachable (link) .gml
--------------------------------------------------------------------------
Returns whether a register is unreachable. Used to perform dead code
elimination.
@param
method emitConstant (link) .gml
--------------------------------------------------------------------------
reg
: Any
The register or accessor to check.
@returns a value of Bool Generates the code to assign a set of constants to a set of
temporary registers.
@param
method emitPermanentConstant (link) .gml
--------------------------------------------------------------------------
value
: Any
The constant value to load.
@returns a value of Any Generates the code to assign a constant to a permanent register.
@param
method emitArgs (link) .gml
--------------------------------------------------------------------------
value
: Any
The constant value to load.
@returns a value of Any Generates the code assign the arguments array into a sequence of
registers.
@param
method emitGlobalGet (link) .gml
--------------------------------------------------------------------------
reg
: Any
The register or accessor containing the register to write to.
NOTE: this will also write values to following `n
`-many registers,
depending on how many arguments you decide to load statically.
Therefore, you should make sure to pre-allocate the registers
for arguments before you make this call.
@param n
: Any
The number of arguments to load.
@returns a value of Any Generates the code to read a global variable.
@param
method emitGlobalSet (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the global to read.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Generates the code to write to a global variable.
@param
method emitReturn (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the global to write to.
@param reg
: Any
The register or accessor containing the value to write.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Generates the code to return a value from this function. Since
statements are expressions, this returns the never register.
@param (optional)
method emitMove (link) .gml
--------------------------------------------------------------------------
reg
: Any
The register or accessor containing the value to return.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Real Generates the code to move the value of one register to another.
@param
method emitClone (link) .gml
--------------------------------------------------------------------------
source
: Any
The register or accessor containing the value to move.
@param dest
: Any
The register or accessor containing the destination to move to.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction. Generates the code to clone a value into a manually managed register.
@param
method emitCloneTemp (link) .gml
--------------------------------------------------------------------------
reg
: Any
The register or accessor containing the value to copy.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction. Generates the code to clone a value into a temporary register. This
is useful for optimising function calls, since it helps align all
arguments so they're adjacent.
@param
method emitJump (link) .gml
--------------------------------------------------------------------------
reg
: Any
The register or accessor containing the value to copy.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction. Generates the code to jump to a new block of code.
@param
method emitJumpFalse (link) .gml
--------------------------------------------------------------------------
block
: Struct.CatspeakBlock
The block to jump to. Generates the code to jump to a new block of code if a condition
is false.
@param
method emitJumpTrue (link) .gml
--------------------------------------------------------------------------
block
: Struct.CatspeakBlock
The block to jump to.
@param condition
: Any
The register or accessor containing the condition code to check. Generates the code to jump to a new block of code if a condition
is true.
@param
method emitCallSelf (link) .gml
--------------------------------------------------------------------------
block
: Struct.CatspeakBlock
The block to jump to.
@param condition
: Any
The register or accessor containing the condition code to check. Generates the code to call a Catspeak function. Returns a register
containing the result of the call. This version takes an additional
argument for setting the "self".
@param
method emitCall (link) .gml
--------------------------------------------------------------------------
self_
: Any
The register or accessor containing self value.
@param callee
: Any
The register or accessor containing function to be called.
@param args
: Array<Any>
The array of registers or accessors containing the arguments to
pass.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Generates the code to call a Catspeak function. Returns a register
containing the result of the call.
@param
method emitSelf (link) .gml
--------------------------------------------------------------------------
callee
: Any
The register or accessor containing function to be called.
@param args
: Array<Any>
The array of registers or accessors containing the arguments to
pass.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Generates the code to get the current "self" context.
@param (optional)
method emitCode (link) .gml
--------------------------------------------------------------------------
pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Emits a new Catspeak intcode instruction for the current block.
Returns the array containing the instruction information.
@param
method emitCodeHoisted (link) .gml
--------------------------------------------------------------------------
inst
: Enum.CatspeakIntcode
The Catspeak intcode instruction to perform.
@param returnReg
: Real
The register to return the value to. If the return value is ignored,
then use `undefined
`.
@param ...
: Any
The parameters to emit for this instruction, can be any kind of
value, but most likely will be register IDs.
@returns a value of Array<Any> Emits a new Catspeak intcode instruction, hoisted into the
initialisation block.
@param
method emitGet (link) .gml
--------------------------------------------------------------------------
inst
: Enum.CatspeakIntcode
The Catspeak intcode instruction to perform.
@param returnReg
: Real
The register to return the value to. If the return value is ignored,
then use `undefined
`.
@param ...
: Any
The parameters to emit for this instruction, can be any kind of
value, but most likely will be register IDs.
@returns a value of Array<Any> Attempts to get the value of an accessor if it exists. If the accessor
does not implement the `
method emitSet (link) .gml
--------------------------------------------------------------------------
getValue
` function, a Catspeak error is
raised.
@param accessor
: Any
The register or accessor to get the value of.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Attempts to get the value of an accessor if it exists. If the accessor
does not implement the `
method lastCode (link) .gml
--------------------------------------------------------------------------
getValue
` function, a Catspeak error is
raised.
@param accessor
: Any
The register or accessor to set the value of.
@param value
: Any
The register or accessor to assign to the accessor
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this instruction.
@returns a value of Any Returns a reference to the last instruction emitted to this function.
If no instruction exists in the current block, `
method lastCodeHoisted (link) .gml
--------------------------------------------------------------------------
undefined
` is returned
instead.
@returns a value of Array<Any> Returns a reference to the last instruction emitted to the
initialisation block, ignoring the final branch instruction. If no
instruction exists, then `
method patchInst (link) .gml
--------------------------------------------------------------------------
undefined
` is returned instead.
@returns a value of Array<Any> Modifies the opcode component of this instruction.
@deprecated This function is deprecated and its usage is discouraged!
@param
method patchInstReturn (link) .gml
--------------------------------------------------------------------------
inst
: Array<Any>
The instruction to modify.
@param code
: Enum.CatspeakIntcode
The opcode to replace the current opcode with. Modifies the return register of this instruction.
@deprecated This function is deprecated and its usage is discouraged!
@param
method patchArg (link) .gml
--------------------------------------------------------------------------
inst
: Array<Any>
The instruction to modify.
@param reg
: Real
The register to return the result of the instruction to. Modifies the return register of this instruction.
Fair warning: this is a dumb operation, so no checks are performed
to validate that the value you're replacing is correct. This may
result in undefined behaviour at runtime! Only use this function
if you absolutely know what you're doing.
@param
method patchPermanentRegisters (link) .gml
--------------------------------------------------------------------------
inst
: Array<Any>
The instruction to modify.
@param argIdx
: Real
The ID of the argument to modify.
@param reg
: Real
The register containing to value to replace. Backpatches the current set of persistent registers, and promotes
them to true registers.
method toString (link) .gml
--------------------------------------------------------------------------
Debug display for Catspeak functions, attempts to resemble the GML
function `
method disassembly (link) .gml
--------------------------------------------------------------------------
toString
` behaviour. Returns the disassembly for this IR function.
struct CatspeakBlock (link) .gml
----------------------------------------------------------------------------
Represents a block of executable code.
@param (optional)
struct CatspeakAccessor (link) .gml
----------------------------------------------------------------------------
name
: Any
The name to give this block, leave blank for no name.
@param (optional) pos
: Struct.CatspeakLocation
The debug info for this block. Represents a special assignment target which generates different code
depending on whether it used as a getter or setter. The simplest example
is with array and struct accessors, but it is not limited to just this.
The `
struct CatspeakReadOnlyAccessor extends CatspeakAccessor (link) .gml
----------------------------------------------------------------------------
getValue
` function expects no arguments and should return a
register ID.
The `setValue
` function expects a single argument, a register containing
the value to set, and should return a register containing the result of
the assignment. If there is no result, return `undefined
`. Used for constants, compile error on attempted assignment to constant
value.
@param
struct CatspeakTempRegisterAccessor extends CatspeakAccessor (link) .gml
----------------------------------------------------------------------------
reg
: Real
The register to mark as read-only. Used for call return values, most cases expect the value to be read once
and then be discarded. This adds a sanity check so that a compiler error
is raised if this fails.
@param
scr_catspeak_intcode (link) .gml
==============================================================================
enum CatspeakIntcode (link) .gml
----------------------------------------------------------------------------
reg
: Real
The register to read from once.
@param ir
: Struct.CatspeakFunction
The IR function associated with this register.
@param (optional) count
: Real
The number of times this register can be read before it's discarded.
Defaults to 1 time. Represents a kind of Catspeak VM instruction.
function catspeak_intcode_show (link) .gml
----------------------------------------------------------------------------
Gets the name for a value of [CatspeakIntcode].
Will return `
function catspeak_intcode_read (link) .gml
----------------------------------------------------------------------------
<unknown>
` if the value is unexpected.
@param value
: Enum.CatspeakIntcode
The value of [CatspeakIntcode] to convert.
@returns a value of String Parses a string into a value of [CatspeakIntcode].
Will return `
function catspeak_intcode_valueof (link) .gml
----------------------------------------------------------------------------
undefined
` if the value cannot be parsed.
@param str
: Any
The string to parse.
@returns a value of Enum.CatspeakIntcode Returns the integer representation for a value of [CatspeakIntcode].
Will return `
function catspeak_intcode_sizeof (link) .gml
----------------------------------------------------------------------------
scr_catspeak_compiler (link) .gml
==============================================================================
undefined
` if the value is unexpected.
@param value
: Enum.CatspeakIntcode
The value of [CatspeakIntcode] to convert.
@returns a value of Real Handles the parsing and codegen stage of the Catspeak compiler.
struct CatspeakCompiler (link) .gml
----------------------------------------------------------------------------
Creates a new Catspeak compiler, responsible for converting a stream of
[CatspeakToken] into executable code.
@param
method advance (link) .gml
--------------------------------------------------------------------------
method matches (link) .gml
--------------------------------------------------------------------------
lexer
: Struct.CatspeakLexer
The iterator that yields tokens to be consumed by the compiler. Must
be a struct with at least a [next] method on it.
@param (optional) ir
: Struct.CatspeakFunction
The Catspeak IR target to write code to, if left empty a new target is
created. This can be accessed using the `ir
` field on a compiler
instance. Returns true if the current token matches this token kind.
@param
method satisfies (link) .gml
--------------------------------------------------------------------------
kind
: Enum.CatspeakToken
The token kind to expect.
@returns a value of Bool Returns true if the current token satisfies a predicate.
@param
method consume (link) .gml
--------------------------------------------------------------------------
predicate
: Function
The predicate to call on the peeked token, must return a Boolean
value.
@returns a value of Bool Attempts to match against a token and advances the parser if there
was a match. Returns whether the match was successful.
@param
method consumeLinebreaks (link) .gml
--------------------------------------------------------------------------
kind
: Enum.CatspeakToken
The token kind to expect.
@returns a value of Bool A helper function which consumes any line breaks which may appear in
an unexpected location.
method error (link) .gml
--------------------------------------------------------------------------
@desc Throws a [CatspeakError] for the current token.
@param (optional)
method errorAndAdvance (link) .gml
--------------------------------------------------------------------------
message
: String
The error message to use. Advances the parser and throws an for the current token.
@param (optional)
method expects (link) .gml
--------------------------------------------------------------------------
message
: String
The error message to use. Throws a [CatspeakError] if the current token is not the
expected token. Advances the parser otherwise.
@param
method expectsSemicolon (link) .gml
--------------------------------------------------------------------------
kind
: Enum.CatspeakToken
The token kind to expect.
@param (optional) message
: String
The error message to use. Throws a [CatspeakError] if the current token is not a semicolon
or new line. Advances the parser otherwise.
@param (optional)
method declareLocal (link) .gml
--------------------------------------------------------------------------
message
: String
The error message to use. Allocates a new register for a local variable and returns its
reference.
@param
method getVar (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the variable to declare.
@param (optional) initReg
: Real
The accessor containing the initialiser expression, or `undefined
`
if there is no initialiser.
@returns a value of Real Looks up a variable by name and returns its register. If the variable
does not exist, then a global constant is loaded from the runtime
interface.
@param
method pushState (link) .gml
--------------------------------------------------------------------------
name
: String
The name of the variable to search for.
@returns a value of Real Stages a new compiler production.
@param
method pushResult (link) .gml
--------------------------------------------------------------------------
state
: Function
The production to insert. Since this is a FIFO data structure, take
care to queue up states in reverse order of the expected execution.
@returns a value of Struct Pushes a register which can be used to pass arguments into compiler
states.
@param
method topResult (link) .gml
--------------------------------------------------------------------------
result
: Any
The result to push onto the stack. Typically this is a register ID. Returns the top result in the result stack without removing it.
@returns a value of Any
method popResult (link) .gml
--------------------------------------------------------------------------
Pops the top value of the result stack and returns it.
@returns a value of Any
method pushBlock (link) .gml
--------------------------------------------------------------------------
Starts a new lexical scope.
@param (optional)
method popBlock (link) .gml
--------------------------------------------------------------------------
inherit
: Bool
Whether to inherit the previous scope, defaults to true. Pops the current block scope and returns its value. Any variables
defined in this scope are freed up to be used by new declarations.
@returns a value of Any
method pushIt (link) .gml
--------------------------------------------------------------------------
Pushes the new accessor for the `
method topIt (link) .gml
--------------------------------------------------------------------------
method popIt (link) .gml
--------------------------------------------------------------------------
it
` keyword onto the stack.
@param reg
: Any
The register or accessor representing the left-hand-side of an
assignment expression. Pops the top accessor the `
method pushLoop (link) .gml
--------------------------------------------------------------------------
it
` keyword represents. Pushes the loop onto the stack.
@param
method topLoop (link) .gml
--------------------------------------------------------------------------
breakBlock
: Struct.CatspeakBlock
The block to jump to if `break
` is used.
@param continueBlock
: Struct.CatspeakBlock
The block to jump to if `continue
` is used.
@param
: Struct Returns the data for the current loop.
@returns a value of Struct
method popLoop (link) .gml
--------------------------------------------------------------------------
Pops the top loop.
method inProgress (link) .gml
--------------------------------------------------------------------------
Returns whether the compiler is in progress.
method emitProgram (link) .gml
--------------------------------------------------------------------------
Performs `
struct CatspeakLocalScope (link) .gml
----------------------------------------------------------------------------
n
`-many steps of the parsing and code generation process.
The steps are discrete so that compilation can be paused if necessary,
e.g. to avoid freezing the game for large files.
@param n
: Real
The number of steps of process. Represents a lexically scoped block of code in the compiler.
@param
struct CatspeakGlobalAccessor (link) .gml
----------------------------------------------------------------------------
parent
: Struct.CatspeakLocalScope
The parent scope to inherit.
@param inherit
: Bool
The whether to actually inherit the parent scope. An accessor for global variable accessor expressions.
@param
struct CatspeakCollectionAccessor (link) .gml
----------------------------------------------------------------------------
compiler
: Struct.CatspeakCompiler
The Catspeak compiler which generated this accessor.
@param name
: String
The name of the global variable. An accessor for array and object access expressions.
@param
scr_catspeak_lexer (link) .gml
==============================================================================
compiler
: Struct.CatspeakCompiler
The Catspeak compiler which generated this accessor.
@param collection
: Any
The register or accessor containing the collection to access.
@param index
: Any
The register or accessor containing the index to access. Handles the lexical analysis stage of the Catspeak compiler.
struct CatspeakLexer (link) .gml
----------------------------------------------------------------------------
Tokenises the contents of a GML buffer. The lexer does not take ownership
of this buffer, but it may mutate it so beware. Therefore you should make
sure to delete the buffer once parsing is complete.
@param
method registerByte (link) .gml
--------------------------------------------------------------------------
buff
: Id.Buffer
The ID of the GML buffer to use.
@param (optional) offset
: Real
The offset in the buffer to start parsing from. Defaults to 0, the
start of the buffer.
@param (optional) size
: Real
The length of the buffer input. Any characters beyond this limit will
be treated as the end of the file. Defaults to `infinity
`. Updates the line and column numbers of the lexer, also updates the.
current length of the lexeme, in bytes.
@param
method registerLexeme (link) .gml
--------------------------------------------------------------------------
byte
: Real
The byte to consider. Registers the current lexeme as a string.
method clearLexeme (link) .gml
--------------------------------------------------------------------------
Resets the current lexeme.
method advance (link) .gml
--------------------------------------------------------------------------
@desc Advances the scanner and returns the current byte.
@returns a value of Real
method peek (link) .gml
--------------------------------------------------------------------------
@desc Peeks `
method advanceWhile (link) .gml
--------------------------------------------------------------------------
n
` bytes ahead of the current buffer offset.
@param n
: Real
The number of bytes to look ahead.
@returns a value of Real @desc Advances the lexer whilst a bytes contain some expected ASCII
descriptor, or until the end of the file is reached.
@param
method nextWithWhitespace (link) .gml
--------------------------------------------------------------------------
predicate
: Function
The predicate to satisfy.
@param (optional) condition
: Bool
The condition to expect. Defaults to `true
`, set the `false
` to
invert the condition.
@returns a value of Real Advances the lexer and returns the next [CatspeakToken]. This includes
additional whitespace and control tokens, like: line breaks `
method next (link) .gml
--------------------------------------------------------------------------
;
`, line
continuations `...
`, and comments `--
`.
@returns a value of Enum.CatspeakToken Advances the lexer and returns the next [CatspeakToken], ingoring
any comments, whitespace, and line continuations.
@returns a value of Enum.CatspeakToken
function catspeak_token_is_operator (link) .gml
----------------------------------------------------------------------------
Returns whether a Catspeak token is a valid operator.
@param
function catspeak_token_is_expression (link) .gml
----------------------------------------------------------------------------
token
: Enum.CatspeakToken
The ID of the token to check.
@returns a value of Bool Returns whether a Catspeak token can start a new expression.
@param
function catspeak_token_skips_newline (link) .gml
----------------------------------------------------------------------------
token
: Enum.CatspeakToken
The ID of the token to check.
@returns a value of Bool Returns whether a Catspeak token ignores any succeeding newline
characters.
@param
function catspeak_string_to_token_keyword (link) .gml
----------------------------------------------------------------------------
token
: Enum.CatspeakToken
The ID of the token to check.
@returns a value of Bool Converts a string into a keyword token if once exists. If the keyword
doesn't exist, `
function catspeak_byte_to_token (link) .gml
----------------------------------------------------------------------------
undefined
` is returned instead.
@param str
: String
The lexeme to look-up the keyword for.
@returns a value of Enum.CatspeakToken Converts an ASCII character into a Catspeak token. This is only an
informed prediction judging by the first character of a token.
@param
scr_catspeak_token (link) .gml
==============================================================================
enum CatspeakToken (link) .gml
----------------------------------------------------------------------------
char
: Real
The character to check.
@returns a value of Enum.CatspeakToken Represents a kind of Catspeak token.
function catspeak_token_show (link) .gml
----------------------------------------------------------------------------
Gets the name for a value of [CatspeakToken].
Will return `
function catspeak_token_read (link) .gml
----------------------------------------------------------------------------
<unknown>
` if the value is unexpected.
@param value
: Enum.CatspeakToken
The value of [CatspeakToken] to convert.
@returns a value of String Parses a string into a value of [CatspeakToken].
Will return `
function catspeak_token_valueof (link) .gml
----------------------------------------------------------------------------
undefined
` if the value cannot be parsed.
@param str
: Any
The string to parse.
@returns a value of Enum.CatspeakToken Returns the integer representation for a value of [CatspeakToken].
Will return `
function catspeak_token_sizeof (link) .gml
----------------------------------------------------------------------------
scr_catspeak_alloc (link) .gml
==============================================================================
undefined
` if the value is unexpected.
@param value
: Enum.CatspeakToken
The value of [CatspeakToken] to convert.
@returns a value of Real The Catspeak engine creates a lot of garbage sometimes, this module is
responsible for the allocation and collection of that garbage.
function catspeak_collect (link) .gml
----------------------------------------------------------------------------
Forces the Catspeak engine to collect any discarded resources.
================================================================================
Futures Reference (link) .md
================================================================================
The [Future library] is used by Catspeak in order to better organise
asynchronous processes. The following sections document its usage.
scr_future (link) .gml
==============================================================================
A [Future] is method of organising asynchronous code in a more manageable
way compared to nested callbacks. This library contains methods of
creating and combining new futures.
enum FutureState (link) .gml
----------------------------------------------------------------------------
struct Future (link) .gml
----------------------------------------------------------------------------
Constructs a new future, allowing for deferred execution of code depending
on whether it was accepted or rejected.
method accept (link) .gml
--------------------------------------------------------------------------
method reject (link) .gml
--------------------------------------------------------------------------
method resolved (link) .gml
--------------------------------------------------------------------------
Returns whether this future has been resolved. A resolved future
may be the result of being accepted OR rejected.
@returns a value of Bool
method andThen (link) .gml
--------------------------------------------------------------------------
Sets the callback function to invoke once the process is complete.
@param
method andCatch (link) .gml
--------------------------------------------------------------------------
callback
: Function
The function to invoke.
@returns a value of Struct.Future Sets the callback function to invoke if an error occurrs whilst the
process is running.
@param
method andFinally (link) .gml
--------------------------------------------------------------------------
callback
: Function
The function to invoke.
@returns a value of Struct.Future Sets the callback function to invoke if this promise is resolved.
@param
function future_all (link) .gml
----------------------------------------------------------------------------
callback
: Function
The function to invoke.
@returns a value of Struct.Future Creates a new [Future] which is accepted only when all other futures in an
array are accepted. If any future in the array is rejected, then the
resulting future is rejected with its value. If all futures are accepted,
then the resulting future is accepted with an array of their values.
@param
function future_any (link) .gml
----------------------------------------------------------------------------
futures
: Array<Struct.Future>
The array of futures to await.
@returns a value of Struct.Future Creates a new [Future] which is accepted if any of the futures in an
array are accepted. If all futures in the array are rejected, then the
resulting future is rejected with an array of their values.
@param
function future_settled (link) .gml
----------------------------------------------------------------------------
futures
: Array<Struct.Future>
The array of futures to await.
@returns a value of Struct.Future Creates a new [Future] which is accepted when all of the futures in an
array are either accepted or rejected.
@param
function future_ok (link) .gml
----------------------------------------------------------------------------
futures
: Array<Struct.Future>
The array of futures to await.
@returns a value of Struct.Future Creates a new [Future] which is immediately accepted with a value.
If the value itself it an instance of [Future], then it is returned
instead.
@param
function future_error (link) .gml
----------------------------------------------------------------------------
value
: Any
The value to create a future from.
@returns a value of Struct.Future Creates a new [Future] which is immediately rejected with a value.
If the value itself it an instance of [Future], then it is returned
instead.
@param
function is_future (link) .gml
----------------------------------------------------------------------------
value
: Any
The value to create a future from.
@returns a value of Struct.Future Returns whether this value represents a future instance.
@param
scr_future_file (link) .gml
==============================================================================
value
: Any
The value to check.
@returns a value of Bool Wrapper functions for file handling tasks.
macro FUTURE_FILE_TITLE (link) .gml
----------------------------------------------------------------------------
The default title used for game saves.
function future_file_read (link) .gml
----------------------------------------------------------------------------
Loads a buffer asynchronously and returns a new [Future]. This future is
accepted if the file was loaded successfully; or rejected if there was a
problem, such as the file not existing.
@param
function future_file_read_string (link) .gml
----------------------------------------------------------------------------
group
: String
The name of the group to match.
@param path
: String
The path of the file to read.
@param (optional) title
: String
The title used to identify this file. Defaults to "Save File".
@returns a value of Struct.Future Similar to [future_file_read], except the result is converted into a
string value.
@param
function future_file_write (link) .gml
----------------------------------------------------------------------------
group
: String
The name of the group to match.
@param path
: String
The path of the file to read.
@param (optional) title
: String
The title used to identify this file. Defaults to "Save File".
@returns a value of Struct.Future Saves a buffer asynchronously and returns a new [Future]. This future is
accepted if the file was saved successfully; or rejected if there was a
problem saving the file.
@param
function future_file_write_string (link) .gml
----------------------------------------------------------------------------
group
: String
The name of the group to match.
@param path
: String
The path of the file to write to.
@param buffer
: Id.Buffer
The ID of the buffer to write.
@param (optional) title
: String
The title used to identify this file. Defaults to "Save File".
@returns a value of Struct.Future Similar to [future_file_write], except the input is converted into a string
buffer before being written to the destination.
@param
================================================================================
Theory (link) .txt
================================================================================
group
: String
The name of the group to match.
@param path
: String
The path of the file to read.
@param value
: Any
The value to write to the file. Implicitly converted into a string.
@param (optional) title
: String
The title used to identify this file. Defaults to "Save File".
@returns a value of Struct.FutureThe challenge Catspeak faces as a modding language for GML is the lack of
threads or syntactic sugar to write proper asynchronous code. Because GML is
(mostly) is a single-threaded language, using a recursive method for parsing
and interpreting the code would cause the application to freeze on very large
inputs. This immediately rules out using recursive descent parsing, pratt
parsing, and tree-walk interpreters.
The problem of interpreting code had an existing solution: use a flat
representation for the executable code. You may have heard of "bytecode" or
"intcode" before, which are both flat representations of code. In fact,
assembly code (which bytecode resembles) is also a flat representation. Not
only would this be faster to execute (in theory), imperative code is very
easy to "pause" compared to recursive approaches.
This idea of a flat execution model was successfully applied to the Catspeak
compiler by using pushdown automata instead of a typical recursive parsing
method. This enables Catspeak programs to be passively compiled, executed, and
paused at any time so the main thread is never blocked by heavy loads.
================================================================================
License (link)
================================================================================
MIT License
Copyright (c) 2021 Katsaii
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--------------------------------------------------------------------------------
|\ /|
>(OwO)< Little Catspeak
\(