โก Installation
Option A โ pip install (recommended)
Install from PyPI to get the cmra command everywhere inside your virtual environment:
# From the project root, with your venv activated:
pip install cmra
# Development install from source (optional):
pip install -e .
# Then run any .cmra or .cmrash file:
cmra myprogram.cmra
Option B โ PowerShell wrapper (no install needed)
.\cmra.ps1 "test cases\test.cmra"
# Add to PATH for this session so `cmra` works anywhere:
$env:PATH = "C:\path\to\CMRA;$env:PATH"
cmra test.cmra
Option C โ Python directly
# Via the installed package:
python -m cmra.cli myprogram.cmra
# Or the legacy single-file interpreters:
python cmra.py myprogram.cmra
python cmrash.py myprogram.cmrash
Option D โ CMRA Esoteric Language Extension
For the best developer experience, install the official extension:
By default, extension run uses python -m cmra "<file>" and can be overridden with cmra.executablePath.
Diagnostics are randomized and themed for .cmra, and concise/technical for .cmrash.
Diagnostic message examples
- Fire Dragon:
Line 4: 'x' is but a myth in this realm. (Hint: bind before use)
- Fire Dragon:
Line 5: Fire Dragon rejects '=' in this chant. (Hint: use bind)
- Shadow Dragon:
Line 4: Undefined variable 'x'. (Hint: initialize with =)
- Shadow Dragon:
Line 5: Unexpected 'bind' in .cmrash. (Hint: use =)
Full diagnostics catalog: cmra-vscode-extension/ERROR_MESSAGES.md.
Option E โ Standalone Executable (Windows)
Don't have Python installed? No problem!
- Executable: Download
cmra.exe from the GitHub Releases, drop it anywhere, and optionally add it to your PATH to run natively.
โถ๏ธ Running Programs
# Basic usage
cmra <filename>
cmrash <filename>
# Examples
cmra "test cases\test.cmra"
cmra projects\calculator.cmra
cmra projects\fizzbuzz.cmra
cmrash "test cases cmrash\test.cmrash"
| Extension | Dialect | Notes |
.cmra | Fire Dragon | Expressive aliases (bind, roar, โฆ) |
.cmrash | Shadow Dragon | Minimal commands (=, print, โฆ) |
Extensions are only conventions โ either interpreter can read any file.
๐ฒ Fire Dragon Syntax
Entry point: cmra.py / src/cmra/fire.py. Expressive, dragon-flavored keywords.
| Keyword | Role | Example |
bind | Assign variable | x bind 5 |
roar | Print value | roar "hello" / roar x + 1 |
sniff | Conditional | sniff x < 10 : roar x |
dive | Direction โ forward | dive |
soar | Direction โ reverse | soar |
murmur | Comment | murmur this is ignored |
Example
x bind 3
name bind "Chimera"
roar name murmur prints: Chimera
roar x * 4 murmur prints: 12.0
๐ Shadow Dragon Syntax
Entry point: cmrash.py / src/cmra/shadow.py. Minimal syntax, same execution model.
| Keyword | Role | Example |
= | Assign variable | x = 5 |
print | Print value | print x + 1 |
check | Conditional | check x < 10 : print x |
reverse | Toggle direction | reverse |
; | Comment | ; this is ignored |
x = 3
name = "Chimera"
print name ; prints: Chimera
๐ข Expressions & Types
- Numbers are always floats:
2 โ 2.0
- Strings use single or double quotes:
"hello" 'world'
- Operators:
+ - * / and comparisons < > <= >= ==
- Precedence:
* / bind tighter than + -, comparisons are lowest
- String + anything โ string concatenation:
"val: " + x โ "val: 5.0"
- Variables are global and persist throughout execution
x bind 4
roar x * 3 + 1 murmur โ 13.0
roar "val: " + x murmur โ "val: 4.0"
roar x == 4 murmur โ 1 (true) or 0 (false)
๐งญ Direction Control
CMRA's defining feature: a global direction controls how the interpreter steps through lines.
| Direction | Value | Movement |
| Forward (default) | 1 | Line 1 โ 2 โ 3 โฆ |
| Reverse | -1 | Line N โ N-1 โ N-2 โฆ |
| Command | Fire Dragon | Shadow Dragon |
| Set forward | dive | โ |
| Set reverse | soar | โ |
| Toggle | โ | reverse |
The program terminates when the instruction pointer goes past the first or last line.
Tip: Prefer soar/dive over reverse in loops โ they are idempotent (calling twice is safe). reverse toggles, so calling it twice cancels out.
๐ฆ Block Conditionals
A block groups multiple lines under a single condition:
sniff x < 5 :
{
roar "x is small"
roar x
}
Block entry rules
| Condition | Direction | Enters at |
| True | Forward | First line of block |
| True | Reverse | Last line of block |
| False | Either | Skip entire block |
This means a soar inside a block takes effect immediately on the reverse pass โ the key to building loops.
๐ Writing Loops
CMRA has no native loop keyword. Use direction reversal + flag guards.
Pattern 1 โ Inline flagged loop
murmur โโ setup โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
i bind 0
flag bind 1
murmur โโ top boundary: re-enter forward if done โ
sniff i < 10 : sniff flag == 0 : dive
murmur โโ flag guard (0 = forward pass) โโโโโโโโโโ
flag bind 0
murmur โโ body: only runs on forward pass โโโโโโโโโ
sniff flag == 0 : roar i
sniff flag == 0 : i bind i + 1
murmur โโ restore flag โโโโโโโโโโโโโโโโโโโโโโโโโโโ
flag bind 1
murmur โโ bottom boundary: reverse if still looping
sniff i < 10 : sniff flag == 1 : soar
How it works step-by-step
- Reaches bottom
sniff โ condition true โ soar โ direction = reverse
- Re-traverses lines in reverse, skipping body (guarded by
flag == 0)
- Reaches top boundary โ
dive โ direction = forward
- Forward pass runs body, increments
i, reaches bottom again
- Repeats until
i < 10 is false
Pattern 2 โ Block loop
i bind 0
flag bind 0
sniff i < 10 :
{
sniff flag == 1 : dive
sniff i < 10 : flag bind 1
sniff flag == 1 : roar i
sniff flag == 1 : i bind i + 1
sniff i < 10 : flag bind 0
sniff flag == 0 : soar
}
Key rule: Always guard loop body lines with a flag variable so the reverse traversal doesn't re-execute them.
โ ๏ธ Common Pitfalls
๐ฅ Missing flag guards โ body runs twice per iteration
murmur BAD โ prints twice per iteration!
roar i
i bind i + 1
murmur GOOD โ only runs on forward pass
sniff flag == 0 : roar i
sniff flag == 0 : i bind i + 1
๐ฅ String growth in loops
Without a flag guard, s bind s + "x" runs on both forward and reverse passes, doubling the string.
Always guard string-building assignments: sniff flag == 0 : s bind s + "x"
๐ฅ Numbers always print as floats
roar 5 prints 5.0, not 5. This is by design โ all numeric literals are floats.
๐ฅ soar vs reverse
soar sets direction to reverse (idempotent)
reverse toggles โ calling it twice cancels out!
- Use
soar/dive in loops for safety
๐ฅ Nested loops need nested flags
Use separate flag variables for each loop level: flag_outer, flag_inner. Every inner body line must be guarded by flag_inner == 0.
๐ฎ Example Programs
Hello World
roar "Hello, Chimera!"
Count 0 to 5
i bind 0
flag bind 1
sniff i <= 5 : sniff flag == 0 : dive
flag bind 0
sniff flag == 0 : roar i
sniff flag == 0 : i bind i + 1
flag bind 1
sniff i <= 5 : sniff flag == 1 : soar
Run the bundled projects
cmra projects\calculator.cmra # factorial, series, power
cmra projects\countdown.cmra # reversible countdown
cmra projects\fizzbuzz.cmra # fizzbuzz 1โ15
cmra projects\story_adventure.cmra # interactive text adventure
Test cases live in test cases\ (Fire Dragon) and test cases cmrash\ (Shadow Dragon).
๐ ๏ธ Extending the Language
To add a new command to the Fire Dragon interpreter (src/cmra/fire.py):
- Top-level dispatch โ add a branch in
execute_line() alongside roar, bind, sniff
- Inline action support โ add it to
execute_inline_action() so it can appear after : in sniff chains
- Test it โ add a
.cmra file to test cases\
Look at how roar, bind, dive, and soar are implemented โ they follow the same two-step pattern.
๐ The full keyword mapping is in keybind.txt โ Fire โ Shadow cheatsheet.