Introduction
Keikaku is a dynamic, interpreted programming language whose defining idea is that its keyword vocabulary should express intent and carry a consistent theme, while its semantics deliver real, non-trivial features: generators with delegation and bidirectional communication, an async/await layer, and a structured error model that treats exceptions as anticipated deviations. The name means “plan,” and the whole vocabulary is organized around planning and foresight. This case study documents the language as it ships: the design of its surface syntax, the semantics behind its generator and async systems, the ANTLR-plus-C implementation, and the cross-platform packaging that delivers it as a working interpreter with a REPL.
I built Keikaku to explore a specific question: how far can a language’s keyword design lean into intent and theme before it stops being practical? The answer the project reaches is that a themed vocabulary and serious language features are not in tension; you can name a conditional foresee and a generator sequence and still ship delegation, transmit/receive, and async/await underneath.
Problem
Scripting languages converge on a shared control-flow vocabulary. if, else, for, while, def, yield, try, except: these are familiar and portable, but they describe mechanism rather than intent, and they carry no thematic coherence. Keikaku’s premise is that the surface vocabulary is a design surface in its own right. A conditional can be named for the act of looking ahead (foresee), a loop for the act of repetition (cycle), a function for a defined procedure (protocol), and error recovery for handling a deviation from the plan (attempt/recover). The problem is not that if/for are broken; it is that they leave expressiveness and aesthetic coherence on the table, and Keikaku sets out to claim both without sacrificing capability.
Background
Keikaku is a dynamic, interpreted language implemented with an ANTLR grammar and a C core, built via CMake and Makefile, packaged with shell scripts, and supported by Python tooling, per the repository’s language breakdown. It is MIT licensed and has a GitHub Actions CI pipeline. Programs run through an interactive REPL (keikaku) or by executing a .kei source file (keikaku script.kei). It is packaged for Arch Linux (makepkg), Debian/Ubuntu/Kali (an install script), and Windows (cross-compiled from Linux to a .exe using mingw-w64-gcc), with a universal CMake build path for other systems.
The feature set is documented across four guides: the language tour (syntax, variables, control flow, functions, data types, built-ins), the generators guide (sequences, delegation, bidirectional communication, generator expressions, exception injection), the async guide (async protocols, await, promises, defer, sleep), and the error-handling guide (attempt/recover, disrupt, anomaly). Those documents are the ground truth for the semantics described here.
Design: The Keyword Vocabulary
The most visible design work is the vocabulary, and it is thematically consistent rather than arbitrary. Variables are designated (with := as a quick-assignment shorthand). Output is declare. Conditionals use foresee for the leading branch, alternate for subsequent conditions, and otherwise for the default, mapping cleanly onto if/else-if/else while reading as acts of anticipation. Loops are cycle, unified across three forms: cycle while cond, cycle through list as item (for-each), and cycle from a to b as i (range). Functions are protocol. Generators are sequence.
The theme extends into the harder features, which is what keeps it from being a superficial reskin. Delegation is delegate (yield-from). Bidirectional communication is transmit (caller to generator) and receive (inside the generator). Advancing a generator is proceed. Injecting an exception into a generator is disrupt. Error recovery is attempt/recover, framed explicitly in the docs as handling “anticipated deviations in the plan.” Even the escape hatch is themed: anomaly marks a block that “executes regardless of standard checks,” for deliberate deviations and prototyping. The built-in functions follow suit: measure (length), span (range list), text/number (conversions), classify (type name). The consistency is the point; the vocabulary is a single designed system, not a scatter of renamed keywords.
Design: Control Flow and Types
Under the themed surface, the control-flow and type model is a conventional, comfortable dynamic-language design, which is a deliberate choice: the novelty is concentrated in the vocabulary and the generator/async semantics, not in reinventing basic evaluation. The data types are integers, floats, strings, booleans, lists (dynamic arrays, [1, 2, 3]), and dictionaries ({key: val}). The three loop forms cover the common iteration needs (condition, collection, range) under one keyword. Functions defined with protocol can yield, and the language treats a protocol with multiple yields as a generator, blurring the function/generator boundary in the same way several mainstream languages do. This familiarity is what lets a reader who has never seen Keikaku predict what a program does after learning only the keyword mapping.
Design: The Generator System
Generators are the centerpiece, and they are unusually complete for a small language. A sequence defines a generator whose execution pauses at each yield; proceed(gen) advances it. That is the baseline. On top of it, three capabilities make the system expressive.
First, delegation: delegate yields all values from another iterable (a generator or a list) inline, so a maintask can delegate subtask() and splice the sub-generator’s output into its own stream (start, then the delegated a, b, then end). This is yield-from, themed.
Second, bidirectional communication: a generator can receive() a value sent by the caller via transmit(gen, value), and yield a response computed from it. The documented echo generator receives "Hello" and yields "You said: Hello". This turns a generator from a one-way producer into a coroutine that consumes and produces.
Third, exception injection: disrupt(gen, error) injects an exception into a running generator at its current suspension point. Combined with an in-generator attempt/recover, this lets a long-lived generator catch an externally-injected fault and continue, as in the documented robust_task that recovers from an injected "Network Failure" and keeps yielding. The three together (delegation, bidirectional flow, injection) make the generator system genuinely coroutine-grade, not just lazy iteration.
Design: Lazy Evaluation
Generator expressions provide lazy sequences inline, written in parentheses: (x * x for x through [1,2,3,4,5]) produces squares on demand, and an optional where clause filters, as in (x for x through [1..6] where x % 2 == 0) for evens. This is the concise, lazy counterpart to writing a full sequence, and it reuses the same through iteration keyword from the loop forms, keeping the surface coherent. Lazy evaluation is a first-class, documented feature rather than an afterthought, consistent with the language’s emphasis on efficient, on-demand data processing.
Design: The Asynchronous Layer
The async layer sits on top of the generator machinery, which is a natural implementation relationship: suspendable generator frames are most of what a coroutine-based async system needs. Keikaku exposes async protocol (and async sequence) for non-blocking functions, await to pause until a promise resolves or a generator yields, and a promise model with resolve to construct an already-resolved promise. Two scheduling primitives round it out: defer(delay, fn, args...) schedules a call for later, and sleep(ms) pauses execution. The documented pattern is idiomatic: an async protocol main() awaits fetch_user(1) and then fetch_posts(user) and declares the results, with await main() driving it. The design mirrors mainstream async/await closely enough to be immediately usable, while keeping the themed protocol/sequence vocabulary.
Design: The Error Model
Error handling is framed thematically as managing deviations from the plan, and it has three parts. attempt/recover is the core try/catch: code that might fail goes in attempt, and control jumps to recover error on failure, binding the error. disrupt is the generator-directed form discussed above, injecting an exception into a running generator. anomaly is a distinctive third construct: a block that “executes regardless of standard checks,” documented for intentional deviations and prototyping. The presence of anomaly as a named, first-class escape hatch is itself a design statement, that deliberately stepping outside the normal control path is a recognized act worth naming, which fits the language’s overall stance that control flow should be explicit and intentional.
Implementation
The implementation is an ANTLR grammar feeding a C interpreter. ANTLR defines the language’s grammar and generates the parsing machinery that turns .kei source into a syntax tree; the C core implements evaluation and the runtime. The runtime carries the state the semantics demand: suspended generator frames (so a sequence can pause at yield and resume on proceed), the caller/generator communication channel (so transmit/receive can pass values both ways), an injection mechanism (so disrupt can raise inside a suspended frame), and the scheduling behavior behind async/await, defer, and sleep. Choosing C for the core is the conventional choice for a portable interpreter that needs to compile cleanly across Linux, Windows (via mingw-w64), and Arch/Debian packaging. Choosing ANTLR for the front end trades writing a parser by hand for a declarative grammar, which is the sensible division of labor for a language whose interesting work is in the runtime semantics rather than in bespoke parsing.
Packaging and Distribution
Keikaku is packaged to be installed, not just built, which is a meaningful amount of delivery engineering for a language project. There are three platform paths plus a universal fallback. Arch Linux uses makepkg -si from packaging/arch. Debian/Ubuntu/Kali use an install script at packaging/debian/install.sh. Windows builds are cross-compiled from Linux to a .exe via packaging/windows/build_exe.sh (requiring mingw-w64-gcc), producing keikaku.exe. For anything else, a universal CMake build (cmake .. && make && sudo make install) works from source. A GitHub Actions CI pipeline backs the repository. The cross-compile-to-Windows-from-Linux path in particular shows the packaging was designed for real distribution across the three ecosystems the author targets, rather than left as a build-it-yourself exercise.
Design Decisions
The central decision was to concentrate novelty in the vocabulary and the generator/async semantics while keeping the rest of the language conventional. A themed keyword set (foresee, cycle, protocol, sequence, transmit, disrupt, anomaly) is paired with familiar dynamic-language types and evaluation, so the language is distinctive to read but predictable to run. A second decision was to make generators coroutine-grade (delegation, bidirectional communication, injection) rather than mere lazy iterators, and then to build async on top of that machinery. A third was to implement with ANTLR plus C, keeping the front end declarative and the runtime portable. A fourth was to invest in real cross-platform packaging so the language ships as an installable interpreter with a REPL.
Tradeoffs
The themed vocabulary trades instant familiarity for expressiveness and coherence: a newcomer must learn that foresee is if and cycle is the unified loop, in exchange for a surface that reads as intent. Keeping the type and evaluation model conventional trades novelty-for-its-own-sake for predictability, which is the right trade when the vocabulary is already the distinctive element. Building async on the generator machinery trades some independence between the two systems for implementation economy, since suspendable frames serve both. Implementing in C trades some development convenience for portability across the packaged platforms. Preserving the two documented output/declaration spellings (designate for declaration, declare for output) rather than collapsing them keeps the docs faithful at the cost of a subtle near-homophone pair a learner must distinguish.
Limitations
Keikaku is a young, single-author language. The documented surface is focused: the four guides cover control flow, generators, async, and error handling thoroughly, but the standard library shown is small (a handful of built-ins: measure, span, text, number, classify, plus declare, proceed, transmit, receive, resolve, defer, sleep). The repository publishes no performance data, so nothing is claimed about interpreter speed. The near-homophone pair designate/declare (declaration versus output) is a small readability trap. These are the honest edges of a focused, expressive, early-stage language.
Future Work
The repository does not publish a roadmap. Grounded, near-term directions implied by the current tree include broadening the architecture layer, expanding the fuzzing corpus categories beyond loader and trace, quantifying decompiler and recovery quality, and publishing the benchmark set. Any specific committed roadmap is Additional validation required.
Lessons Learned
The clearest lesson is that a themed keyword vocabulary and serious language features coexist comfortably: Naming a generator sequence and an injection disrupt does not prevent them from being a full coroutine system. A second lesson is that concentrating novelty in the vocabulary and the generator/async semantics, while keeping types and evaluation conventional, keeps the language learnable despite its unfamiliar surface. A third is that building async on top of suspendable generator frames is an economical implementation path, one runtime mechanism serving both. A fourth, from the packaging, is that shipping a language means shipping installers: the Arch/Debian/Windows-cross-compile paths are as much a part of the project as the interpreter.
Conclusion
Keikaku is a designed language that commits to an idea, that surface vocabulary can express intent and carry a theme, and backs it with a real implementation. Under a plan-themed keyword set (foresee, cycle, protocol, sequence, transmit, receive, disrupt, anomaly) sits a coroutine-grade generator system with delegation and bidirectional communication, an async/await layer built on that machinery, a structured error model, and an ANTLR-plus-C interpreter packaged for Arch, Debian, and Windows with a REPL and file execution. It is expressive by design and conventional where it should be, and it ships as a working, installable language rather than a sketch.
REGAAN R