A tiny, embeddable and statically typed programming language inspired by C and Python, targeting WebAssembly, x86-64, and ARM64.
You can try out Cyth in the web playground: https://cyth.vldr.org
Suppose we want to call a native C function from Cyth; for example, to print the 12th fibonacci number. In Cyth, you just import the function and call it:
import "std"
void print(string text)
int fibonacci(int n)
if n <= 1
return n
else
return fibonacci(n - 2) + fibonacci(n - 1)
print("Fibonacci = " + fibonacci(12))On the C side, we have to just initialize the Cyth runtime, provide our implementation of print and run the program:
#include <stdio.h>
#include <cyth.h>
void print(String *string) {
printf("%s\n", string->data);
}
int main(int argc, char *argv[]) {
Jit* jit = cyth_init(argv[1], NULL, NULL);
if (!jit)
return -1;
cyth_set_function(jit, "std.print.void(string)", (uintptr_t)print);
cyth_generate(jit, 0);
cyth_run(jit);
cyth_destroy(jit);
return 0;
}That is it. With just a few lines of code, Cyth can call into C, and C can call back into Cyth.
If you're interested, you can look at some of the examples or read through the overview of the language.
Precompiled binaries are available in Releases.
- Raylib
Cyth with Raylib bindings, allowing direct access to Raylib functions from a Cyth script file.
To build Cyth, you will need to have CMake and gcc/clang/MSVC installed. To run the test suite, you will need to have Node.js (v20 or higher) installed.
If you want to build the WASM backend, provide the -DWASM=1 flag to CMake.
Note: The supported platforms for the JIT compiler are:
- Windows x64 and ARM64
- Linux x64 and ARM64
- MacOS x64 and ARM64
Run the following commands from the root directory (in a terminal):
Debug:
cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -S . -B build
cd build
makeRelease:
cmake -DCMAKE_BUILD_TYPE=Release -S . -B build
cd build
makeManual C compilation:
cc third_party/mir/mir.c third_party/mir/mir-gen.c third_party/bdwgc/extra/gc.c src/jit.c src/checker.c src/environment.c src/main.c src/memory.c src/lexer.c src/map.c src/parser.c -Ithird_party/mir -Ithird_party/bdwgc/include -fsigned-char -O3 -o cyth
Run the following commands from the root directory (in a terminal):
Xcode project:
cmake -S . -B xbuild -G Xcode
Then, in the xbuild directory, open cyth.xcodeproj in Xcode.
Makefile (Debug):
cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=1 -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -S . -B build
cd build
makeMakefile (Release):
cmake -DCMAKE_BUILD_TYPE=Release -S . -B build
cd build
makeRun the following commands from the root directory (in a terminal):
Visual Studio 2022 project:
cmake.exe -S . -B winbuild -G "Visual Studio 17 2022"
Visual Studio 2026 project:
cmake.exe -S . -B winbuild -G "Visual Studio 18 2026"
Then, in the winbuild directory, open cyth.sln / cyth.slnx in Visual Studio.
For web builds, you will need to have Emscripten installed.
Run the following commands from the root directory (in a terminal):
Debug:
emcmake cmake -DCMAKE_BUILD_TYPE=Debug -S . -B embuild
cd embuild
make
Release:
emcmake cmake -DCMAKE_BUILD_TYPE=Release -S . -B embuild
cd embuild
make
- Primitive Types
- Types
- Variables
- Functions
ifstatementwhileloopforloopbreakstatementcontinuestatement
Possible values: false or true
Default value: false
Example:
bool myBool = truePossible values: 0 to 255
Default value: '\0'
Example:
char myChar = 'a'Possible values: -2147483648 to 2147483647
Default value: 0
Example:
int myInt = 10Possible values: ± 1.5 x 10−45 to ± 3.4 x 1038
Default value: 0.0
Example:
float myFloat = 12.25Possible values: UTF-8 text
Default value: "" (empty string)
- All types can be cast to a
string, which will convert to the type's string representation; castinganyto a string will attempt to convert theanyto the underlying string type rather than its string representation.
Example:
string myString = "hello world"Possible values: null, string, Array or Object
Default value: null
- Casting
anyto the incorrect underlying type will trigger a panic.
Example:
any myAny = "hello world"
string myString = (string)myAnyPossible values: Empty list or a list of one or more elements.
Default value: [] (empty list)
- Arrays can be multi-dimensional.
- All arrays are dynamic, meaning they can be resized.
Example:
int[] myArray
myArray.push(1)
myArray.push(2)
myArray.push(3)
string[][] myArray2D = [["I'm", "multidimensional"]]Possible values: null or a valid pointer (reference).
Default value: null
Example:
class Vector
float x
float y
float z
void __init__(int x, int y, int z)
this.x = x
this.y = y
this.z = z
Vector myVector = Vector(10, 20, 30)Although the keyword class is used, there is no support for inheritance or other common object-oriented concepts in Cyth.
Objects in Cyth closely resemble structs rather than proper classes, except there are method functions. All method functions have an implicit this parameter.
Example:
class Vector
float x
float y
float z
float length()
return (x*x + y*y + z*z).sqrt()Cyth objects are compatible with C structs. In C, the Vector object would look like:
struct Vector { float x; float y; float z; };Calling the
lengthmethod function from C would look like:typedef float (*LengthFunction)(Vector*); LengthFunction length = (LengthFunction) cyth_get_function(jit, "Vector.length.float()"); Vector vec = {1.0f, 1.0f, 1.0f}; float len = length(&vec);
Objects have special method functions:
Constructors
void __init__()Index overload
V __get__(T index)Index and assign overload
V __set__(T index, U value)Operator overloads
V __add__(T other)
V __sub__(T other)
V __div__(T other)
V __mul__(T other)
V __mod__(T other)
V __and__(T other)
V __or__(T other)
V __xor__(T other)
V __lshift__(T other)
V __rshift__(T other)
V __lt__(T other)
V __le__(T other)
V __gt__(T other)
V __ge__(T other)
V __eq__(T other)
V __ne__(T other)
V __str__(T other)Possible values: null or a valid pointer (reference).
Default value: null
- Function pointers cannot be placed into
any(limitation added due to WASM not supporting them). - Function pointers compatible with C function pointers.
Example:
int adder(int a, int b)
return a + b
int(int, int) myFunctionPointer = adder
myFunctionPointer(10, 20)Example (Function Member):
class Vector
float x
float y
float z
float length()
return (x * x + y * y + z * z).sqrt()
Vector myVector = Vector()
float(Vector) myFunctionPointer = Vector.length
myFunctionPointer(myVector)You can declare variables like this:
int myVariable = 12
float mySecondVariableIf you do not initialize a variable, a default value is assigned automatically. For example, mySecondVariable will be set to 0.0.
You can declare variables in the top-level scope of your program which will make them a global variable.
You can easily access global variables from C using
cyth_get_variable.For example, to get
myVariablefrom C, you would write:int* myVariable = (int*) cyth_get_variable(jit, "myVariable.int");The address returned from
cyth_get_variablewill beNULLif it was not found, or the signature is incorrect.Make sure to only call
cyth_get_variableafter callingcyth_run, otherwise global variables will be uninitialized which can lead to issues if you're using types that have special default initializations (like arrays and strings).
You can declare functions like this:
int myFunction(int a, int b)
return a + bYou can place functions inside other functions:
int myFunction(int a, int b)
int myInnerFunction(int c)
return 2 * c
return myInnerFunction(a + b)Nested functions are not closures, meaning they can't access variables outside their body.
Functions can appear inside objects making them method functions:
class MyClass
int a
int b
int myFunction()
return this.a + this.bMethod functions have an implicit this parameter which is a pointer to the object itself. This can be null if the method is called on a null pointer.
class MyClass
int a
int b
int myFunction()
int myInnerFunction()
return 2 * (this.a + this.b)
return myInnerFunction()Nested functions inside method functions are themselves method functions with an implicit this parameter. Meaning these nested method functions can access object fields inside them.
You can declare if statements like this:
bool condition
if condition
# true
else if not condition
# else if
else
# falseYou can declare a while loop like this:
bool condition = true
while condition
# while loopYou can declare a C-style for loop like this:
for int i = 0; i < 10; i += 1
# for loopsYou can also declare a for each loop like this:
for int number in [1, 2, 3]
# for each loopThe index of the element is stored into an implicit it variable.
You can use break to immediately exit a loop:
for int i = 0; i < 10; i += 1
# Exit when i == 5
if i == 5
breakYou can use continue to immediately start the next iteration of a loop:
for int i = 0; i < 10; i += 1
# Skip iteration when i == 5
if i == 5
continue