Riddle is a programming language that transpiles to Glosure.
python riddle.py [options] <input.riddle> [output.gls]
Run without arguments to start the REPL — an interactive prompt where you can type Riddle code and see the transpiled output immediately.
| Flag | Description |
|---|---|
--no-attribution |
Omit the attribution header |
--minify |
Collapse all whitespace and remove comments for a compact one-line output |
--minify-glosure |
Minify a Glosure (.gls) file directly: strip ;; comments and collapse whitespace (no transpilation) |
--no-time |
Omit the transpilation time output |
--no-length |
Omit the character length output |
--no-output |
Suppress transpiled code output to stdout (only applies when no output file is specified) |
REPL exit commands: //exit, //quit, //close, Ctrl-Z/EOF.
Include another Riddle source file with the #include directive. Paths relative to the file containing the directive are resolved from that file's directory; absolute paths are also supported. Includes are processed recursively.
Wildcards (*, ?, **) are supported — matching files are included in sorted order.
#include "lib.riddle";
#include "C:/Projects/helpers.riddle";
#include "../shared/utils.riddle";
#include "src/helpers/*";
#include "plugins/**/*.riddle";
Every statement must end with a semicolon — including bare literals, assignments, expressions, and return. #include directives must also end with a semicolon.
Code blocks are delimited by braces. Indentation matters only for readability.
Comments begin with //.
Conditions in if, for, foreach and while do NOT use parentheses around the condition — just write the expression directly.
Identifiers can contain letters, digits, underscores and hyphens. They may end with ! or ?. Valid names:
gl-break-silence
empty?
effectful!
multiplayer?
my_var2
Boolean values are true and false.
| Operators | Description |
|---|---|
&& |
Logical AND (short-circuit) |
|| |
Logical OR (short-circuit) |
! |
Logical NOT |
==, != |
Equality |
Numbers are stored in full precision. Negative literals (e.g. -145) are supported directly.
| Operators | Description |
|---|---|
+, -, *, / |
Standard arithmetic |
% |
Modulo |
^ |
Power |
==, !=, >, >=, <, <= |
Comparison |
Strings are written in double quotes. Use \" to include a literal quote inside the string. Other escape sequences like \n, \t and \\ are also supported.
print("Hello \"world\"!");
| Operators | Description |
|---|---|
[i] |
Get character at index i |
The null value represents the absence of a value.
Lists are written in square brackets. Access elements with a 0-based index.
list = [1, 2, 3];
print(list[0]); // 1
list[1] = 42;
| Operators | Description |
|---|---|
[i] |
Get/set element at index i |
Dictionaries map keys to values. Inline literals accept any expression as a key, separated from the value by ::
dict = {"name": "Riddle", 0: "zero", null: "nothing", true: "bool"};
Access or assign with any expression as the key via []:
print(dict["name"]);
dict["version"] = 2;
dict[some_variable] = "dynamic";
| Operators | Description |
|---|---|
[k] |
Get/set value with key k |
Use = to create a new variable binding:
a = 0;
b = "hello";
c = [1, 2, 3];
A second = with the same name creates a new binding in the current scope — it does NOT mutate the original.
Use <- to reassign an existing variable in place:
a = 0;
a <- 1; // a is now 1
Compound operators apply an arithmetic operation and assign the result in one step:
| Operator | Equivalent to |
|---|---|
a += b |
a <- a + b |
a -= b |
a <- a - b |
a *= b |
a <- a * b |
a /= b |
a <- a / b |
a ^= b |
a <- a ^ b |
a %= b |
a <- a % b |
Prefix and postfix forms are both supported:
++a; // increment a by 1 (value used after increment)
a++; // increment a by 1 (value used before increment)
--a; // decrement a by 1
a--; // decrement a by 1
| Category | Operators |
|---|---|
| Assignment | =, <-, +=, -=, *=, /=, ^=, %= |
| Increment / Decrement | ++x, x++, --x, x-- |
| Arithmetic | +, -, *, /, %, ^ |
| Comparison | ==, !=, <, >, <=, >= |
| Logical | &&, ||, ! |
| Type check | isa |
| Arrow (method) | -> |
A namespace block creates a dict and scopes its member definitions inside it:
namespace MyApp {
x = 1;
defun greet(name) {
print(name);
}
function helper() {
return x;
}
}
This transpiles as:
MyApp = {};
MyApp.x = 1;
defun MyApp.greet(name) {
print(name);
}
function MyApp.helper() {
return x;
}
Namespaces can be nested:
namespace Outer {
namespace Inner {
val = 42;
}
}
Use if blocks to branch on a condition. Include zero or more else if blocks and one optional else block.
if condition {
body
} else if other_condition {
other_body
} else {
else_body
}
if a > b {
print("a is bigger");
} else if a < b {
print("b is bigger");
} else {
print("equal");
}
Use a while loop to repeat as long as a condition is true.
while condition {
body
}
i = 0;
while i < 10 {
print(i);
i <- i + 1;
}
A foreach loop iterates over a collection, binding the index and value to variables.
foreach index value in collection {
body
}
foreach idx val in ["apple", "banana", "cherry"] {
print([idx, val]);
}
A for loop repeats with an initializer, condition, and step expression.
for init; condition; step {
body
}
for i = 0; i < 10; i <- i + 1 {
print(i);
}
Define a host function with function or a Glosure function with defun.
The difference is in how they are called at runtime:
functioncreates a Glosure defunction — resolved via the host function lookup mechanismdefuncreates a Glosure defun — resolved via the Glosure function lookup mechanism
Both support default parameter values:
function add(a, b = 0) {
return a + b;
}
defun multiply(a, b = 1) {
return a * b;
}
print(add(3, 4)); // 7
print(multiply(5, 2)); // 10
Methods on namespaced objects use dot notation in the definition:
function namespace.functions.Hello() {
print("Hello!");
}
Create an anonymous host function with glosure or anonymous Glosure function with lambda.
glosure (params) {
body
}
apply = glosure (f, x) {
return f(x);
};
somelist.apply(glosure (a1, a2 = 0) {
print(a1);
});
Use -> to call a method on an object, passing the object as the first argument.
obj->method(args)
sequence->len(); // equivalent to ((at sequence 'len') sequence)
Use . to call a method on an object without passing the object.
obj.method(args)
d.test(3, 4); // equivalent to ((at d 'test') 3 4)
Access nested object properties with ..
namespace.variables.shell