Notes
2026/06/29
Here's a sketch of a simple language for expressing rules of arbitrary writing systems in a chat app without using Unicode.
The language is event driven. Functions are only invoked in response to keypresses (on a user defined on-screen keyboard with arbitrary layout). Each key corresponds to exactly one function. There is no other way to execute code.
A function can freely read and set variables. Reading a variable that hasn't been set (as a result of an earlier keypress) returns nil. Variables can be manually cleared by setting them to nil. A function doesn't return anything, its implicit effect is its entire world state, meaning the final value of all variables.
offset = 10
cursor = (0, 0)
A variable belongs either to the user that pressed the key (in which case the variable is mutable for that user) or to the other user (in which case it is read-only for the current user and must be prefixed with other. to be accessed).
offset = other.offset + 10
cursor = other.cursor + (0, offset)
There are two special variables: canvas and history.
canvas variable, which is a list of pairs of (glyph, position).history variable, which is a list of pairs of (keypress, world_state). The history variable is always read-only.(Undo is not part of the language but is a built-in function of the system that cannot be accessed or changed from within the rule language. The undo system is the only way to undo a keypress and pop a history entry.)
The language only allows bounded loops. The only iteration construct is a for loop bounded by either a number (of iterations) or a list (which iterates through the list, each element at a time). There is no recursion.
for x in 0..n {
// do something
}
for x in list {
// do something
}
The only way to branch conditionally is if-else (with optional else if clauses).
if x < 5 {
// do something
} else if x < 10 {
// do something
} else {
// do something
}
The built-in types are glyphs, (fixed precision) numbers, booleans, tuples, and lists. There are no user-defined types. Tuples can only be accessed by fully destructuring them, lists can only be accessed by iterating over them.
// tuple destructuring
(x, y) = point
// list iteration
for x in [1, 2, 3] {
// do something
}
There is no list mutation. New lists can only be created as literals or using a limited form of list comprehension (similar to Python, but more general, like Dart's collection expressions).
// 0, 2, 4, ...
[for x in 0..n {
x * 2
}]
// 1, 1, 2, 4, 3, 9, ...
[for x in 1..n {
...[x, x * x]
}]
// 0, 2, 4, 6, ...
[for x in 0..n {
if x % 2 == 0 {
x
}
}]
There are built-in functions for the standard arithmetic and trigonometric operations on numbers. Function definitions can be used to share functionality between different keypress handlers.
This language should feel pretty standard. Deliberately Turing-incomplete, with limited abstraction, no user-defined types, and a slightly imperative feel. No first class functions. No recursion. (Simple enough that static types with explicit function parameter type annotations and without generics should be sufficient.)