Error-Lang ("Error Language") is a teaching-first programming language where code intentionally breaks. The first task in any Error-Lang exercise is to make it build.
Error-Lang turns the compiler toolchain into the curriculum. Every run produces at least one new syntax error, but students can always make progress because the system is designed for recovery and diagnosis.
-
Error-Lang is NOT for production use
-
Error-Lang is NOT a replacement for any serious language
-
Error-Lang does NOT aim for performance
-
Error-Lang errors are NOT bugs - they are the curriculum
Every injected error has:
-
A unique error code (
E0001,E0002, etc.) -
A learning objective
-
A recovery path
-
A lesson in the curriculum
Error-Lang maintains a Stability Score starting at 100. Each run’s injected error reduces the score. At S=0, execution still works but output becomes "wobbly":
-
Variables reorder in debug printing
-
Whitespace in pretty printer gets chaotic
-
Semantics remain deterministic
This creates the "it’s working, but it’s falling apart" aesthetic.
Where Jenga Semantics decay the whole program, Echo types decay a single value — deliberately, observably, and irreversibly. Error-Lang is a decompositional language: when structure is lost, the loss must be seen.
-
Echo<A, B>— a retained witnessx : Aplus the visible outputy : Bit reached. -
EchoR<A, B>— the non-recoverable residue after erasure (the witness is gone). -
echo_to_residue(e)— the explicit decomposition step,Echo<A,B> → EchoR<A,B>, which debits the Stability Score.
The governing rule is decomposition must be visible: echo_to_residue is
never a silent cast, EchoR is never an Echo with a missing field, and the
stability debit is never hidden. See docs/Echo-Decomposition.adoc and
spec/type-system.md §7.
Error-Lang uses a Julia-inspired, block-based syntax.
# A complete Error-Lang program
main
let greeting = "Hello, Error-Lang!"
println(greeting)
gutter
# Error injection zone - something WILL break here
let broken = "this might not parse
end
println("Still running!")
end| Keyword | Purpose |
|---|---|
|
Program entry point block |
|
Block terminator |
|
Variable binding |
|
Error injection zone (safe to break) |
|
Conditionals (Stage 2+) |
|
Function definition (Stage 2+) |
|
Fibre type: retained witness + visible output ( |
|
Residue type: non-recoverable remains after erasure ( |
| Type | Example | Notes |
|---|---|---|
Integer |
|
64-bit signed |
Float |
|
IEEE 754 double |
String |
|
Double-quoted, escapes supported |
Boolean |
|
let x = 42
let message = "Hello"
let result = x + 10
let e: Echo<Int, String> = echo(42, "answer") # type annotation: a fibre witnesslet e = echo(42, "answer") # Echo<Int, String>: witness 42 reached "answer"
let i = echo_input(e) # 42 — recover the witness
let o = echo_output(e) # "answer" — the visible output
let r = echo_to_residue(e) # EchoR<Int, String> — witness erased; stability drops
let still = echo_output(r) # "answer" — output survives erasure
let lost = residue_strictly_loses(r) # true — non-recoverability is observable
# echo_input(r) # ERROR: the witness is gone (decomposition is real)The gutter block is a designated area where errors will be injected.
The parser will encounter an error here on some runs.
gutter
# Anything here might break
let x = ...
endParser recovery rule: on gutter error, skip tokens until end and continue
main program execution.
Every Error-Lang error follows this format:
Error-LangError: <file>:<line>:<col>: <message> [code=E#### run=NNN]
Example:
Error-LangError: hello.err:7:23: unterminated string literal [code=E0002 run=3]
| Code | Description | Learning Objective |
|---|---|---|
E0001 |
Unexpected token |
Token classification |
E0002 |
Unterminated string |
String literal rules |
E0003 |
Invalid escape sequence |
Escape processing |
E0004 |
Illegal character |
Character sets |
E0005 |
Missing 'end' |
Block structure |
E0006 |
Unmatched parenthesis |
Expression nesting |
E0007 |
Unicode/smart quote |
Encoding awareness |
E0008 |
Identifier rules violation |
Naming conventions |
E0009 |
Reserved keyword misuse |
Keyword awareness |
E0010 |
Whitespace significance |
Indentation rules |
Error-Lang tracks execution count in .error-lang/state.json:
{
"runCounter": 5,
"stabilityScore": 80,
"lastError": "E0002",
"seed": 12345
}Each run:
-
Reads current run counter
-
Selects error injection based on (seed, runCounter)
-
Injects error into gutter zone
-
Parses with recovery
-
Executes valid portions
-
Updates state file
error-lang run file.err # Run program
error-lang run file.err --seed 42 # Deterministic mode
error-lang run file.err --run-id 5 # Specific run numbererror-lang doctor # Check environment
error-lang doctor --verbose # Detailed diagnosticserror-lang explain E0002 # Explain error code
error-lang explain --all # List all error codesprogram = main_block ;
main_block = "main" , statements , "end" ;
statements = { statement } ;
statement = let_stmt
| print_stmt
| gutter_block
| expression ;
let_stmt = "let" , IDENTIFIER , "=" , expression ;
print_stmt = ( "print" | "println" ) , "(" , [ expr_list ] , ")" ;
gutter_block = "gutter" , { token } , "end" ;
expr_list = expression , { "," , expression } ;
expression = logical_or ;
logical_or = logical_and , { "or" , logical_and } ;
logical_and = equality , { "and" , equality } ;
equality = comparison , { ( "==" | "!=" ) , comparison } ;
comparison = term , { ( "<" | ">" | "<=" | ">=" ) , term } ;
term = factor , { ( "+" | "-" ) , factor } ;
factor = unary , { ( "*" | "/" | "%" ) , unary } ;
unary = ( "-" | "not" ) , unary | primary ;
primary = INTEGER | FLOAT | STRING | BOOL | IDENTIFIER | "(" , expression , ")" ;
IDENTIFIER = LETTER , { LETTER | DIGIT | "_" } ;
INTEGER = [ "-" ] , DIGIT , { DIGIT } ;
FLOAT = INTEGER , "." , DIGIT , { DIGIT } ;
STRING = '"' , { character } , '"' ;
BOOL = "true" | "false" ;.err file
│
▼
┌─────────┐ tokens ┌────────┐ AST ┌──────────┐
│ Lexer │ ──────────▶ │ Parser │ ───────▶ │ Executor │
└─────────┘ └────────┘ └──────────┘
│ │ │
│ │ ▼
└────────┬───────────────┴──────────────▶ Output
│
▼
┌─────────────┐
│ Diagnostics │ ──▶ Error-LangError messages
└─────────────┘MUST implement:
-
main/endblocks -
letbindings -
print/println -
Integer and string literals
-
Basic arithmetic
-
gutterblock with recovery -
Single error injection per run
-
Run counter tracking
MUST implement Level 1 plus:
-
error-lang doctor -
error-lang explain -
Deterministic
--seedmode -
10 error codes minimum